【Ansible】大量のサーバにDNSの向け先変更を実施する

こんにちは、キクです。

最近になって少しずつAnsibleを利用することにも慣れてきました。

先日、大量のサーバを対象にDNS設定を変更する案件がありました。
そこで「Ansibleで自動化できないか?」と思い立ち、「これはいい練習になりそう!」と思ったのでチャレンジしました。

本記事では、Ansibleで大量のサーバにDNS設定変更処理を実施した方法をご紹介します。
と言っても非常にシンプルなのでサクッと行きましょう!

それでは、よろしくお願いします。

背景

まず、今回の作業の概要と背景について簡単に触れておきます。

現在利用しているDNSサーバの稼働環境が丸ごとなくなるというのがそもそもの背景でした。

そのため、新しい環境にDNSサーバを構築し、旧DNSサーバを利用する設定になっているサーバ群に対して「新DNSサーバを使いなさい」という設定を行う必要がありました。

台数にして60台以上のサーバが対象となるため「手動ではやってられん!」と思い、Ansibleでの自動化に踏み切りました

なお、今回の作業対象は本番稼働中のサーバではあるものの、万が一名前解決ができなくなったとしてもクリティカルな影響が出るサーバではありませんでした。

そのため、比較的ラフに作業を実施しましたが、名前解決がシビアなシステムにおいてはもう少し丁寧に作業をしてもいいかもしれないといった内容になっています。

作業1. インベントリファイルの作成

対象ホストへの接続で利用するインベントリファイルを作成していきます。

各サーバはいくつかのグループに分類されるため、それを考慮してインベントリファイルを記載していきます。

$ vi inventory/hosts
[groupA]
192.168.1.1
192.168.1.2
・・・
192.168.1.20

[groupB]
192.168.1.21
192.168.1.22
・・・
192.168.1.40

[groupC]
192.168.1.41
192.168.1.42
・・・
192.168.1.60

作業2. Playbookの作成

続いて、本体となるPlaybookを作成していきます。
今回は複雑な作業も特にないので、ひとつのplaybookに直書きしちゃいます。

構成としては以下3ステップになります。

  1. 既存resolv.confのバックアップ
  2. resolv.confの修正
  3. 名前解決テスト

$ vi playbook.yml
- name: Manage resolv.conf
  hosts: all
  become: true
  tasks:
    - name: Create a custom backup of resolv.conf
      command: cp /etc/resolv.conf /etc/resolv.conf.ansible_bak

    - name: Replace nameserver in resolv.conf
      lineinfile:
        path: /etc/resolv.conf
        regexp: '^.*\\bnameserver\\b.*192\\.168\\.2\\.53.*$'
        line: 'nameserver 192.168.3.53'
        state: present
        backup: no

    - name: Verify DNS resolution with ping
      shell: ping -c 3 www.test.co.jp
      register: ping_result
      failed_when: ping_result.rc != 0
      ignore_errors: true
      changed_when: false
ポイント①

新しい設定を記載したresolv.confを作成して既存ファイルと差し替えるという案もありましたが、全サーバで既存ファイルが同じ内容か不明でした。
もし一部サーバで特殊な設定が含まれていた場合、共通で差し替えてしまうと厄介なことになりそうだと考えました。

そのため、テキストファイルを行単位で編集できる「lineinfileモジュール」なるものを利用して対応しました。

ポイント②

処理の最後には「名前解決テスト」を実施するようにしました。

Ansibleのフローで「Replace nameserver in resolv.conf」のステータスがOKであれば変更自体はできているものと思いますが、「本当に名前解決できるよね?」の確認を込めて追加しています。

ちなみに、作業対象サーバにdigコマンドが入っていなかったのでpingでの確認としました。

備忘

ignore_errors: true

名前解決が失敗した場合でも後続処理は流したかった

changed_when: false

shellモジュールを使用すると、コマンドの実行そのものを「変更(changed)」として扱ってしまうようで、それだとpingがどうだったのか判断がしづらかったです。

そのため、本設定を入れることで「OK」または「FAILED」の表示になるようにしました。

作業3. Playbookの実行

各グループ毎にPlaybookを実行してDNS設定を変更していきます。

$ ansible-playbook -u testuser playbook.yml -i inventory/hosts -l groupA -K -k --diff
$ ansible-playbook -u testuser playbook.yml -i inventory/hosts -l groupB -K -k --diff
$ ansible-playbook -u testuser playbook.yml -i inventory/hosts -l groupC -K -k --diff

以下は実行例になります。

$ ansible-playbook -u testuser playbook.yml -i inventory/hosts -l groupA -K -k --diff
SSH password:
BECOME password[defaults to SSH password]:
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details

PLAY [Manage resolv.conf] **********************************************************************

TASK [Gathering Facts] *************************************************************************
ok: [192.168.1.1]
ok: [192.168.1.2]
~中略~
ok: [192.168.1.20]

TASK [Create a custom backup of resolv.conf] ***************************************************
changed: [192.168.1.1]
changed: [192.168.1.2]
~中略~
changed: [192.168.1.20]

TASK [Replace nameserver in resolv.conf] *******************************************************
+++ after: /etc/resolv.conf (content)
@@ -1,2 +1,2 @@
 # Generated by NetworkManager
-nameserver 192.168.2.53
+nameserver 192.168.3.53

changed: [192.168.1.1]
--- before: /etc/resolv.conf (content)
+++ after: /etc/resolv.conf (content)
@@ -1,2 +1,2 @@
 # Generated by NetworkManager
-nameserver 192.168.2.53
+nameserver 192.168.3.53

changed: [192.168.1.2]

~中略~

--- before: /etc/resolv.conf (content)
+++ after: /etc/resolv.conf (content)
@@ -1,2 +1,2 @@
 # Generated by NetworkManager
-nameserver 192.168.2.53
+nameserver 192.168.3.53

changed: [192.168.1.20]

TASK [Verify DNS resolution with ping] *********************************************************
ok: [192.168.1.1]
ok: [192.168.1.2]
~中略~
ok: [192.168.1.20]

PLAY RECAP *******************************************************************************************************
192.168.1.1                : ok=4    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
192.168.1.2                : ok=4    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
~中略~
192.168.1.20               : ok=4    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
内容の確認
TASK [Create a custom backup of resolv.conf] ***************************************************
changed: [192.168.1.1]
changed: [192.168.1.2]
~中略~
changed: [192.168.1.20]

作業前のバックアップ取得が正常に行われました。

TASK [Replace nameserver in resolv.conf] *******************************************************
--- before: /etc/resolv.conf (content)
+++ after: /etc/resolv.conf (content)
@@ -1,2 +1,2 @@
 # Generated by NetworkManager
-nameserver 192.168.2.53
+nameserver 192.168.3.53

changed: [192.168.1.1]
--- before: /etc/resolv.conf (content)
+++ after: /etc/resolv.conf (content)
@@ -1,2 +1,2 @@
 # Generated by NetworkManager
-nameserver 192.168.2.53
+nameserver 192.168.3.53

changed: [192.168.1.2]

~中略~

--- before: /etc/resolv.conf (content)
+++ after: /etc/resolv.conf (content)
@@ -1,2 +1,2 @@
 # Generated by NetworkManager
-nameserver 192.168.2.53
+nameserver 192.168.3.53

changed: [192.168.1.20]

正規表現にマッチした既存の「nameserver 192.168.2.53」から新たに「nameserver 192.168.3.53」に差し替えているのが分かります。

TASK [Verify DNS resolution with ping] *********************************************************
ok: [192.168.1.1]
ok: [192.168.1.2]
~中略~
ok: [192.168.1.20]

作業後のpingによるドメイン指定での疎通確認も全台「ok」となっており、問題なく名前解決ができていることが確認できました。

すべての処理が想定通りに動いていたので、今回の作業は無事完了しました。

まとめ

今回はDNSサーバの切り替えに伴うresolv.confファイルの修正をAnsibleで大量のサーバに一気にやってしまおうという内容でした。

改めて、今回は以下の内容を実施しました。

今回実施した作業

1. 既存resolv.confのバックアップ

cpコマンドでresolv.confファイルのバックアップを作成

2. resolv.confの修正

nameserverとして192.168.2.53(旧DNS)を指定している行を192.168.3.53(新DNS)に修正

3. 名前解決テスト

ドメイン指定のpingを実施して名前解決ができるか確認

まだまだAnsible初心者ではありますが、今後も少しずつ活用の幅を広げて知見を深めていきと思います!

本記事を最後まで読んでいただき、ありがとうございました。
ではでは!

-Ansible
-,