Ansibleプレイブックを1台のマシンに安全に制限しますか?


227

コンピューターの小さなグループでの簡単なユーザー管理タスクにAnsibleを使用しています。現在、私はプレイブックを設定しhosts: allていて、hostsファイルは単一のグループであり、すべてのマシンがリストされています。

# file: hosts
[office]
imac-1.local
imac-2.local
imac-3.local

私は頻繁に1台のマシンをターゲットにしなければならないことに気づきました。このansible-playbookコマンドは、次のように再生を制限できます。

ansible-playbook --limit imac-2.local user.yml

しかし、それは、特に潜在的に破壊的なプレイブックにとっては、壊れやすいもののようです。limitフラグを除外すると、プレイブックがどこでも実行されることになります。これらのツールはたまにしか使用されないので、間違いのない再生に一歩踏み出す価値があるように思われます。

プレイブックの実行を1台のマシンに制限するためのベストプラクティスはありますか?理想的には、いくつかの重要な詳細が省略された場合、プレイブックは無害である必要があります。

回答:


209

プレイブックにホスト名を直接入力できることが判明したため、プレイブックを実行すると問題hosts: imac-2.localなく動作します。しかし、それはちょっと不格好です。

より良い解決策は、変数を使用してプレイブックのホストを定義し、次のようにして特定のホストアドレスを渡すことです--extra-vars

# file: user.yml  (playbook)
---
- hosts: '{{ target }}'
  user: ...

プレイブックを実行する:

ansible-playbook user.yml --extra-vars "target=imac-2.local"

もし {{ target }}が定義されていない、プレイブックは何もしません。必要に応じて、hostsファイルのグループもパススルーできます。全体として、これは潜在的に破壊的なプレイブックを構築するためのはるかに安全な方法のようです。

単一のホストを対象とするハンドブック:

$ ansible-playbook user.yml --extra-vars "target=imac-2.local" --list-hosts

playbook: user.yml

  play #1 (imac-2.local): host count=1
    imac-2.local

ホストのグループを含むハンドブック:

$ ansible-playbook user.yml --extra-vars "target=office" --list-hosts

playbook: user.yml

  play #1 (office): host count=3
    imac-1.local
    imac-2.local
    imac-3.local

ホストの定義を忘れても安全です!

$ ansible-playbook user.yml --list-hosts

playbook: user.yml

  play #1 ({{target}}): host count=0

52
これは、と1.5.3で解決可能である--limit office[0]
NG。

4
変数は引用符で囲む必要があります。つまり'{{ target }}'-docs.ansible.com/…に
Limbo Peng

9
これは、他のいくつかの回答とは異なり、「フェイルセーフ」の回答です。何かを省略しても、何も起こりません。Ansible 1.7を使用して「1つだけ」のホストで実行するrun_onceことは、それでも破壊的である可能性があるため、それほど良い考えではありません。
RichVel

4
短いコマンドが必要な場合-eは、と同等です--extra-vars
William Turrell

1
:あなたのansible構成はホストは空にすることはできませんか、そしてなど、神社のフィルタ作品と組み合わせ変数を使用して未定義する必要がある場合hosts: "{{ target | default('no_hosts')}}"
ザックWEG

178

コマンドラインで単一のホスト(または、おそらく複数のホスト)を、中間のインベントリなしで指定できるようにする、かわいい小さなトリックもあります。

ansible-playbook -i "imac1-local," user.yml

最後のコンマ()に注意してください。これは、ファイルではなくリストであることを示しています。

これで、誤って実際のインベントリファイルを渡してしまった場合は保護されません。そのため、この特定の問題に対する適切な解決策ではない可能性があります。しかし、知っておくと便利です。


2
すごいです。私は定期的に-lフラグを使用します。これはetc / ansible / hosts(EC2検出APIを使用して入力されます)で動作しますが、実際には1台のマシンが必要なだけです。ありがとうございました!
ビック

3
このトリックは、hostsファイルを使用する必要がありますか?AWS EC2システムの動的インベントリとしてホストを使用していますが、次を返します:skipping: no hosts matched。おそらく、このトリックは機能してから--limit機能しなくなりますか?
hamx0r

1
このトリックは私にはうまくいきませんでした。しかし、これはうまくいきました$ ansible-playbook -kK --limit=myhost1 myplaybook.yml。マーワンの答えを見てください。
Donn Lee

2
これが機能するためには、ホストallがプレイに設定されている必要があることに注意してください。これには、少し時間がかかりました...
Remigius Stalder

83

このアプローチは、play_hosts変数をチェックして複数のホストが提供されている場合に終了します。失敗モジュールは、単一のホスト条件が満たされない場合に終了するために使用されます。以下の例では、2つのホストaliceとbobを持つhostsファイルを使用しています。

user.yml(プレイブック)

---
- hosts: all
  tasks:
    - name: Check for single host
      fail: msg="Single host check failed."
      when: "{{ play_hosts|length }} != 1"
    - debug: msg='I got executed!'

ホストフィルターなしでプレイブックを実行する

$ ansible-playbook user.yml
PLAY [all] ****************************************************************
TASK: [Check for single host] *********************************************
failed: [alice] => {"failed": true}
msg: Single host check failed.
failed: [bob] => {"failed": true}
msg: Single host check failed.
FATAL: all hosts have already failed -- aborting

単一のホストでプレイブックを実行する

$ ansible-playbook user.yml --limit=alice

PLAY [all] ****************************************************************

TASK: [Check for single host] *********************************************
skipping: [alice]

TASK: [debug msg='I got executed!'] ***************************************
ok: [alice] => {
    "msg": "I got executed!"
}

1
間違いなく最高の1つ--limitは行く方法です
Berto

7
play_hostsはAnsible 2.2で非推奨になり、に置き換えられましたansible_play_hosts。を必要とせずに1つのホストで実行するには--limit、を使用できますwhen: inventory_hostname == ansible_play_hosts[0]
Trevor Robinson

[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: {{ play_hosts|length }} == ''Ansible 2.8.4。
トーマス

32

私見にはもっと便利な方法があります。実際、次のおかげで、プレイブックを適用したいマシンをユーザーにインタラクティブにプロンプ​​トすることができますvars_prompt

---

- hosts: "{{ setupHosts }}"
  vars_prompt:
    - name: "setupHosts"
      prompt: "Which hosts would you like to setup?"
      private: no
  tasks:
    […]

2
とてもかっこいい。これには、プレイブックがインベントリファイルに固有ではないという利点もあります。
Erfan、

2
編集用THX!なぜ入力がデフォルトで「パスワード形式」で扱われるのかと実際に思っていました。私はそれをドキュメントで見逃していた:)
Buzut

コマンドラインからホスト変数を設定して、このプレイブックのプロンプトを削除できますか?
andig

1
@andig with --extra-varsand and a normal var in your
playbook

実際、私はこれを機能させることができませんでした- {{ hosts }}値が入力される前に評価されているようです-または特別なトリックはありますか?
Remigius Stalder 2017

18

joemailerの回答を拡張するには、リモートマシンの任意のサブセットに一致するパターンマッチング機能が必要な場合( ansibleコマンドと)、すべてのマシンで誤ってプレイブックを実行することを非常に困難にしたい場合、これは私が思いついたもの:

他の回答と同じプレイブック:

# file: user.yml  (playbook)
---
- hosts: '{{ target }}'
  user: ...

次のホストを用意しましょう:

imac-10.local
imac-11.local
imac-22.local

ここで、すべてのデバイスでコマンドを実行するには、ターゲット変数を「すべて」に明示的に設定する必要があります

ansible-playbook user.yml --extra-vars "target=all"

そしてそれを特定のパターンに制限するために、あなたは設定することができます target=pattern_here

または、引数を残しtarget=allて追加することもでき--limitます。例:

--limit imac-1*

すなわち。 ansible-playbook user.yml --extra-vars "target=all" --limit imac-1* --list-hosts

その結果:

playbook: user.yml

  play #1 (office): host count=2
    imac-10.local
    imac-11.local


13

私はすべての答えがどれほど複雑であるかを本当に理解していません、それを行う方法は単純です:

ansible-playbook user.yml -i hosts/hosts --limit imac-2.local --check

このcheckモードでは、何も変更せずに予行モードで実行できます。


7
おそらく回答について疑問に思っているため、誤ってパラメーターが省略された場合に実行されないようにする方法を求める質問を逃しました。要件に反するパラメーターをさらに追加することを提案しました。
techraf 2017年

2
ああ、確かに、でも、人々が私に賛成する場合、それは彼らがAnsible初心者(私が私の回答を書いたときのように)である--checkため、フラグについてさえ知らないためである可能性があります。この質問は非常にググる
knocte

6

EC2外部インベントリスクリプトを使用するAWSユーザーは、単にインスタンスIDでフィルタリングできます。

ansible-playbook sample-playbook.yml --limit i-c98d5a71 --list-hosts

これは、インベントリスクリプトがデフォルトグループを作成するため機能します


4
オプション--limitはEC2に限定されず、インベントリの名前をホスト/グループ化するために使用できます。ありがとう。
martinezdelariva 2015年

5

多数のチームが使用できる一般的なプレイブックがいくつかあります。複数のグループ宣言を含む環境固有のインベントリファイルもあります。

誰かがプレイブックを呼び出して実行するグ​​ループを指定するように強制するには、プレイブックの上部にダミーのエントリをシードします。

[ansible-dummy-group]
dummy-server

次に、共有プレイブックの最初のステップとして次のチェックを含めます。

- hosts: all
  gather_facts: False
  run_once: true
  tasks:
  - fail:
      msg: "Please specify a group to run this playbook against"
    when: '"dummy-server" in ansible_play_batch'

このプレイブックが実行される予定のホストのリスト(ansible_play_batch)にダミーサーバーが表示される場合、呼び出し元はグループを指定していないため、プレイブックの実行は失敗します。


ansible_play_batchは現在のバッチのみをリストするため、バッチ処理を使用する場合、これはまだ安全ではありません。ansible_play_hosts代わりに使用することをお勧めします。
トーマス

それとは別に、このトリックは最も単純で、尋ねられたものに最も近いようです。採用しています!
トーマス

4

バージョン1.7以降、ansibleにはrun_onceオプションがあります。セクションには、他のさまざまな手法についての議論も含まれています。


4

これは、ターゲットサーバー自体でプレイブックを実行する方法を示しています。

ローカル接続を使用する場合、これは少しトリッキーです。しかし、hosts設定に変数を使用し、hostsファイルにlocalhostの特別なエントリを作成する場合、これは問題ありません。

(すべての)プレイブックでは、hosts:行が次のように設定されています。

- hosts: "{{ target | default('no_hosts')}}"

インベントリのhostsファイルに、接続をローカルに設定するlocalhostのエントリを追加します。

[localhost]
127.0.0.1  ansible_connection=local

次に、コマンドラインで、ターゲットを明示的に設定するコマンドを実行します-例:

$ ansible-playbook --extra-vars "target=localhost" test.yml

これはansible-pullを使用するときにも機能します。

$ ansible-pull -U <git-repo-here> -d ~/ansible --extra-vars "target=localhost" test.yml

コマンドラインで変数を設定するのを忘れた場合、コマンドは安全にエラーになり(「no_hosts」という名前のホストグループを作成していない限り)、次の警告が表示されます。

skipping: no hosts matched

上記のように、(hostsファイルにある限り)次のようにして単一のマシンをターゲットにすることができます。

$ ansible-playbook --extra-vars "target=server.domain" test.yml

または次のようなグループ:

$ ansible-playbook --extra-vars "target=web-servers" test.yml

0

私はプロビジョンと呼ばれるラッパースクリプトを使用してターゲットを選択するように強制するので、他の場所で処理する必要はありません。

気になる人のために、私のvagrantfileが使用するオプションにENV変数を使用し(クラウドシステムに対応するansible引数を追加)、残りのansible引数を通過させます。一度に10台を超えるサーバーを作成してプロビジョニングする場合、失敗したサーバーでの自動再試行を含めます(進行中の場合)-一度に100台ほどのサーバーを作成すると、いくつかのサーバーで初めて失敗することがよくあります)。

echo 'Usage: [VAR=value] bin/provision [options] dev|all|TARGET|vagrant'
echo '  bootstrap - Bootstrap servers ssh port and initial security provisioning'
echo '  dev - Provision localhost for development and control'
echo '  TARGET - specify specific host or group of hosts'
echo '  all - provision all servers'
echo '  vagrant - Provision local vagrant machine (environment vars only)'
echo
echo 'Environment VARS'
echo '  BOOTSTRAP - use cloud providers default user settings if set'
echo '  TAGS - if TAGS env variable is set, then only tasks with these tags are run'
echo '  SKIP_TAGS - only run plays and tasks whose tags do not match these values'
echo '  START_AT_TASK - start the playbook at the task matching this name'
echo
ansible-playbook --help | sed -e '1d
    s#=/etc/ansible/hosts# set by bin/provision argument#
    /-k/s/$/ (use for fresh systems)/
    /--tags/s/$/ (use TAGS var instead)/
    /--skip-tags/s/$/ (use SKIP_TAGS var instead)/
    /--start-at-task/s/$/ (use START_AT_TASK var instead)/
'

0

少し異なる解決策は、Ansibleの現在の実行に対してCLIオプションのansible_limit内容である特殊変数を使用すること--limitです。

- hosts: "{{ ansible_limit | default(omit) }}"

ここで追加の変数を定義する必要はありません--limit。フラグを指定してプレイブックを実行するだけです。

ansible-playbook --limit imac-2.local user.yml
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.