マニュアル: Ansible

投稿日: 更新日:

独自ドメインを作りました

今後はこちらに移行していく予定です。

環境変数

設定

Ansible Configuration Settings — Ansible Documentationより。

adhoc実行

例えば以下のコマンドで、対象マシンの情報が得られる。

ansible all -i ホスト名, -m setup

オプションは以下の意味を持つ。

  • all: ホスト名のパターン。通常は all
  • -i <ホスト名 or IPアドレス>: インベントリ文字列、ホスト名の最後に,をつけるのを忘>れないこと1
  • -m: 起動するモジュール

よく使う起動オプション

  • -i <インベントリファイル>: インベントリファイルを指定
  • -C: 実行しない(dry run)
  • -D: 結果の差分表示
  • -t <タグ>: 指定したタグのみ実行
  • --step: タスクごとに確認を行う。
  • --syntax-check: 文法チェックを行う。
  • -l <パターン>: 指定したパターンにマッチするホストのみ処理

環境変数

  • ANSIBLE_KEEP_REMOTE_FILES
    • この値を1にすると、リモートの一時ファイルをクリーンアップしない。デバッグ時に便利。

インベントリファイル

1つのホストに2つのポートは設定できない(回避策あり)

インベントリファイルに以下のように記述しても、意図した通りに動きません。 グループを分けてもダメです。

[some_group]
foo.example.com:1111
foo.example.com:1234

この指定ができないことで何が困るのかというと、 SSH接続ポートを変えてPlaybookを2つ管理したい場合に困ります。

ただし、これには回避策があります。

GitHubにあるIssue Cannot specify two different ports to the same host in inventoryのリンク先にある python - Ansible multiple hosts with port forwarding - Stack Overflowで書かれているように、 ansible_hostansible_portを使って書きます2

変更があったときだけ実行

いくつか方法がある。 1つ目は、handlerを使う(notifyの項目参照)。 2つ目は、registerで値を代入して、whenを使う方法。 rebootはこれでないとうまく動かなかった。

- file: state=...
  register: foo

- file: ...
  when: foo.changed

変数定義

以下の場所に書ける。

  • group_vars
  • host_vars
  • インベントリ中
  • roles/ロール/vars/
  • set_fact

set_fact

set_fact中で複数定義する場合、 同じset_fact中で定義されている他の変数は参照できない。 以下のように書くとエラーになる。

- set_fact:
    value_a: "abc"
    value_b: "{{ value_a }}def"

notify

ハンドラが呼ばれるタイミング

roleを使用する場合は、tasks3の終了タイミングで呼ばれる4

handlers notified within roles section are automatically flushed in the end of tasks section, but before any tasks handlers.

ハンドラを強制的に呼ぶ方法

metaモジュールの flush_handlers を使うと、そのタイミングでハンドラが呼ばれます。

ハンドラで複数のタスクをこなす方法

今はサポートされていないようです。チケットに代替案があります。

Add support for blocks in role handlers · Issue #14270 · ansible/ansible

ロール

ロール単位での実行オプションはないようです。 自分でtagsを付けるしかありません。

ループ

  • Loops — Ansible Documentation

  • with_items

    • 配列を取る。
    • 配列の値が文字列のときは、{{ item }}として値を取得。
    • 配列の値がハッシュのときは、{{ item.name }}などとして値を取得する。
  • with_nested

    • 配列の配列を取る。
    • 値は先頭に定義されたものから、{{ item[0] }}などとして値を取得。

モジュール

ファイルの展開

unarchiveを使う。

  • コピー元の指定に注意
    • デフォルト: srcローカルファイルと解釈して、リモートに転送して解凍
    • remote_src=yes がある場合
      • src://がある場合はURLと解釈してダウンロード
      • それ以外のときは、ターゲットホストのパスと解釈して実行
  • チェックサムは未対応
    • Issue #13665に挙がっている通り、チェックサムには未対応です。
      • get_urlモジュールを使ってからダウンロードが良いと思います。

ファイルの取得(ダウンロード)

get_urlを使う。 Proxyが環境変数で設定されているときは、Proxyを使用します。

大きいファイルをダウンロードする時は、checksumを付けること。 checksumを付けると、ダウンロード前にチェックサムを調べて、 一致していたらダウンロードしません。

if a checksum is passed to this parameter, and the file exist under the dest location, the destination_checksum would be calculated, and if checksum equals destination_checksum, the file download would be skipped (unless force is true).

- get_url:
    url: http://example.com/path/
    dest: /root/
    checksum: sha256:xxxx

対応しているチェックサムは、sha1は対応しているようですが、 それ以外はpythonのバージョンによるので分からないみたいです。 ソースコード見れば分かるかも。。。

文字列置換

  • 1行の追加・置き換え: lineinfile
  • ブロックの追加: blockinfile
    • 既存のブロックの置き換えには向いていない。
  • ブロックの置き換え: replace
    • これだけUTF-8以外をサポート。

ファイルごと置き換えていいのであれば、template、 またはcopyのcontentもアリだと思います。

AWS

MySQL

Google Cloud

Google Cloud Platform Guide

認証

サービスアカウントを作成する。

  1. 左上のメニューから、「IAMと管理」→「サービスアカウント」を選択
  2. 「サービスアカウントを作成」をクリック
  3. 値を入力
    • サービスアカウント名: サービスの内容を表す文字列(日本語でもOK)
    • 役割: 必要な役割を追加
      • 例: Google Cloud DNS: DNS→DNS管理者
    • サービスアカウントID: 一意のものを割り当て
    • 新しい秘密鍵の提供: オン、キーのタイプはJSON
  4. 作成ボタンを押すと、JSONファイルがダウンロードされる。

Ansibleでは以下のように使用する。 まず、資格情報を直接渡す場合(秘密鍵を直接指定するので注意)。

  • credentials_file: 秘密鍵の入ったJSONファイル。
    • パスはプロジェクトトップからの相対パスが使用可能(roles/xxx/filesではない)
  • service_account_email: サービスアカウントID(gserviceaccount.com)
  • project_id: プロジェクトID

DB作成時のみインポートする方法

以下のように、mysql_dbが実行されたときだけインポートするのが良いと思います。

テンプレート

Jinja2を使う。

  • 制御
    • {%%} で囲む。
    • ifendif のように囲む。
  • 空白の制御(Whitespacde Control
    • {%--%} のように囲む。
    • Ansibleから使用する場合は、Jinja2を制御するためのヘッダが書ける(Notes)。
      • #jinja2: trim_blocks: "true", lstrip_blocks: "true"のように書ける。

フィルタ

変数名の後に|(パイプ)を付けることで、フィルタできる。

個人的に気をつけていること

  • ファイル変更後にリロードしたいときは、notifyを使う。
  • nameには変数を使わない。環境変数は$VALみたいな書き方をする。
    • --start-atとかで指定しづらいため。
  • 何百台もデプロイする場合は別として、手動での作業を無理に排除しない。
    • 例: サーバ再起動とかOracleのインストーラとか
    • とは言え手作業はなるべく減らしたいので、開発環境のマスタ設定は行う。
  • 大きいファイルは手元に置かない。http経由で取得。

ディレクトリ構成

自分の場合、開発環境はVagrantですが、本番環境はオンプレや、VMなど様々です5。 なので、以下の要件を満たす必要があります。

  • Vagrantとそれ以外を同一のPlaybookで扱いたい
  • しかし、初期設定やテストデータは分離したい

この場合、以下のようなディレクトリ構成にしています。

  • Vagrantfile
  • bootstrap.sh: Vagrant起動時に読み込まれるスクリプト。
    • yum updateや最低限のユーザ作成など。
    • AWSではcloud-initとう仕組みがありますが、これを意識したものです。
  • pre-install
    • Vagrant固有の初期設定。
    • 開発時はsshで作業する事が多いので、そのままrootになれるようにしています。
  • ansible
    • Vagrantと本番環境共通の設定。
  • post-install
    • テストデータなど、開発環境固有の設定。

この場合の難点は、Ansibleの変数が共有できないことですが、 以下のようにVagrantから変数を定義することで対処可能です。

  config.vm.provision "ansible" do |ansible|
    ansible.host_vars = {
      "default" => {
        "key" => "val"
      }
    }
    ansible.playbook = "ansible/site.yml"
  end

  1. カンマで終わるとホスト指定になる仕様については、man ansibleに記載されています。 ↩︎

  2. StackOverFlowでは ansible_ssh_host, ansible_ssh_port と書かれていますが、これは古い書き方です。 ↩︎

  3. 記載はありませんが、rolesでも同じみたいです。 ↩︎

  4. Intro to Playbooks — Ansible Documentation ↩︎

  5. Docker使えているところはその悩みはないと思いますが。。。 ↩︎

公式サイト

外部サイト

逆引きマニュアル