Ansibleでファイルを書き換える時の5パターン

Apr 21, 2015   #ansible 

Ansibleで設定ファイルを書き換える時に使うモジュールを紹介します。

パターンとしては5種類が考えられます。 それぞれ特徴があるので、状況に応じて使い分けするのが良いと思います。

モジュール名 特徴
lineinfile 単一行の追記と置換を行います。
オプションが多く複雑な行の指定ができます。
replace 複数行の置換が可能ですが、追記ができません。
lineinfileと比べてオプションが少なめで、細かな操作は苦手です。
ini_file INI形式専用の編集コマンドです。
command sedコマンド等を使って、モジュールの制約を受けずに編集できます。
ただし、冪等性は自分で保証する必要があります。
copy ローカルからリモートにファイルを送り込んで置き換える方法です。
各サーバで固有の設定があると厳しいです。

一番最後で、設定変更後のサービス再起動に便利なnotify / handlerも紹介します。

lineinfile

単一行の追記、もしくは置換を行います。 複数行の置換が必要なケースでは、replaceモジュールを使用します。 ちなみに、lineinfileregexpで複数行マッチした場合は一番最後の行が置換対象になります。

主要なオプション

主要なオプションは下記の通りです(*…必須 )。

オプション名 コメント
dest * 編集対象のファイルパスを指定します。
line 挿入する、もしくは置換後の文字列を指定します。
regexp 置換対象を正規表現で指定します。正規表現はPythonの書式に従います。
backup yesにすると、変更対象のバックアップを保存します。バックアップファイル名の書式は、元ファイル名.2015-04-20\@23:26:17~です。
create yesにすると、対象ファイルが存在しない場合は新規に作成します。

サンプル

例1) /etc/cloud/cloud.cfgファイルにlocale: ja_JP.UTF-8を追記(最終行)する。

---
  tasks:
  - name: set locale
    lineinfile: >
      dest=/etc/cloud/cloud.cfg
      line='locale: ja_JP.UTF-8'

例2) /etc/cloud/cloud.cfgファイルのrepo_upgrade:が含まれる行をrepo_upgrade: noneに置換する。

---
  tasks:
  - name: disable repo_upgrade
    lineinfile: >
      dest=/etc/cloud/cloud.cfg
      regexp='repo_upgrade\:'
      line='repo_upgrade: none'

参考URL

lineinfile - Ansible Documentation

replace

複数行の置換を行います。 バージョン1.6から追加されたモジュールです。

主要なオプション

主要なオプションは下記の通りです(*…必須 )。

オプション名 コメント
dest * 置換対象のファイルパスを指定します。
replace 置換後の文字列を指定します。
regexp 置換対象を正規表現で指定します。正規表現はPythonの書式に従います。
backup yesにすると、変更対象のバックアップを保存します。バックアップファイル名の書式は、元ファイル名.2015-04-20\@23:26:17~です。

サンプル

例1) /etc/sysconfig/clockファイルのZONE="UTC"から始まる行をZONE="Asia/Tokyo"に置換する。

  - name: set timezone
    replace: >
      dest=/etc/sysconfig/clock
      regexp='^ZONE="UTC"'
      replace='ZONE="Asia/Tokyo"'

参考URL

replace - Ansible Documentation

ini_file

INI形式のファイルを編集します。

主要なオプション

主要なオプションは下記の通りです(*…必須 )。

オプション名 コメント
dest * 編集対象のファイルパスを指定します。
section * 編集対象のセクション名を指定します。
option 編集対象の行の名前を指定します。
value 編集対象の行の値を指定します。
backup yesにすると、変更対象のバックアップを保存します。バックアップファイル名の書式は、元ファイル名.2015-04-20@23:26:17~です。

サンプル

例1) /home/ec2-user/test.iniファイルの[section1]内にhoge = 100という行を追記する。

  - name: ini_file module test
    ini_file: >
      dest=/home/ec2-user/test.ini
      section=section1
      option=hoge
      value=100

参考URL

ini_file - Tweak settings in INI files — Ansible Documentation

command

リモートで指定したコマンドを実行します。

主要なオプション

主要なオプションは下記の通りです(*…必須 )。

オプション名 コメント
free_form * 便宜上free_formという名前が付いていますが、実行するコマンドのことです。
chdir コマンド実行前に、指定したディレクトリに移動します。
creates yesにすると、指定したファイルが存在する場合コマンドは実行されません。
removes yesにすると、指定したファイルが存在しない場合コマンドは実行されません。

サンプル

例1) /home/ec2-user/ディレクトリに移動してから、sed -i -e "s/hoge/fuga/g" command-testコマンドを実行する。

- name: command module test
  command: 'sed -i -e "s/hoge/fuga/g" command-test'
  args:
    chdir: /home/ec2-user/

注意点

commandモジュールはパイプやリダイレクトが使えないので、必要に応じてshellモジュールを使用します。 commandshellもオプションは同じです。 ただし、どちらも使える状況であればcommandを使うことが推奨されています(下記引用を参照)。

If you want to execute a command securely and predictably, it may be better to use the command module instead. Best practices when writing playbooks will follow the trend of using command unless shell is explicitly required. When running ad-hoc commands, use your best judgement.
引用元:shell - Execute commands in nodes.

参考URL

command - Ansible Documentation
shell - Ansible Documentation

copy

ローカルのファイルをリモートにコピーします。

主要なオプション

主要なオプションは下記の通りです(*…必須 )。

オプション名 コメント
src コピー元のファイルもしくはディレクトリを指定します。絶対パスでも相対パスでも指定が可能です。ディレクトリの場合、パス指定の仕方でコピーする対象が変わります(詳しくは後述)。
dest * コピー先を絶対パスで指定します。srcでディレクトリを指定した場合、destもディレクトリである必要があります。
force yesにすると、コピー先のファイルは強制的に置き換えられます。デフォルトはyesです。
owner 所有ユーザを指定できます。
group 所有グループを指定できます。
mode 権限を指定できます。chmodの絶対モードかシンボリックモードを使います。

サンプル

例1) ローカルにあるsrc_fileファイルを、リモートにdest_fileファイルとしてコピーする。

  - name: copy module test
    copy: >
      src=/home/ec2-user/src_file
      dest=/home/ec2-user/dest_file

注意点

srcオプションでディレクトリのパスを指定する場合、末尾の/の有無により動作が変わります。

/が無い場合、local_dirディレクトリが丸ごとコピーされます。

  - name: copy module test
    copy: >
      src=path/local_dir
      dest=path/remote_dir

/が有る場合、local_dir/*がコピーされます。

- name: copy module test
  copy: >
    src=path/local_dir/
    dest=path/remote_dir/

参考URL

copy - Ansible Documentation

handlersを使ったサービス再起動

設定ファイルの書き換え後にサービスを再起動する場合、notify / handlersが便利です。 下記はローカルのhttpd.confをリモートにコピーし、httpdを再起動するPlaybookです。

---
- hosts: all
  remote_user: ec2-user
  sudo: yes
  gather_facts: no

  tasks:
    - name: copy httpd.conf
      copy: >
        src=/home/ec2-user/httpd.conf
        dest=/etc/httpd/conf/httpd.conf
      notify: apache restart

  handlers:
    - name: apache restart
      service:
        name=httpd
        state=restarted

tasksセクションにnotify: apache restartと記載しています。 これは、copyの結果がchangedの場合、handlersapache restartを実行するという意味です。 結果がok(処理されなかった)であればサービスは再起動されません。

tasks:
  - name: copy httpd.conf
    copy: >
      src=/home/ec2-user/httpd.conf
      dest=/etc/httpd/conf/httpd.conf
      notify: apache restart

handlersセクションでは、単純にserviceモジュールを使ってhttpdを再起動しているだけです。 nameの値は、notifyの値と一致させる必要があります。

handlers:
  - name: apache restart
    service:
      name=httpd
      state=restarted

ちなみに、Playbook中に何度notify: apache restartと書いてもapache restartは1回だけしか実行されません。 handlerは全てのtasksが終わった後に、1度だけ実行されます。