it-swarm.com.de

Ansible Playbooks sicher auf eine einzige Maschine beschränken?

Ich verwende Ansible für einige einfache Benutzerverwaltungsaufgaben mit einer kleinen Gruppe von Computern. Derzeit habe ich meine Playbooks auf hosts: all gesetzt und meine hosts-Datei ist nur eine einzige Gruppe, in der alle Maschinen aufgeführt sind:

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

Ich habe häufig festgestellt, dass ich mich auf eine einzelne Maschine konzentrieren muss. Der Befehl ansible-playbook kann die Anzahl der Spiele wie folgt begrenzen:

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

Aber das scheint irgendwie fragil zu sein, vor allem für ein potenziell zerstörerisches Spielbuch. Wenn Sie das Flag limit auslassen, wird das Playbook überall ausgeführt. Da diese Tools nur gelegentlich verwendet werden, lohnt es sich, eine narrensichere Wiedergabe zu unternehmen, damit wir nicht versehentlich in einigen Monaten Nuke machen.

Gibt es eine bewährte Methode, um Playbook-Läufe auf einen einzelnen Computer zu beschränken? Idealerweise sollten die Spielbücher harmlos sein, wenn einige wichtige Details ausgelassen wurden.

182
joemaller

Es stellt sich heraus, dass es möglich ist, einen Hostnamen direkt in das Playbook einzugeben, sodass das Playbook mit hosts: iMac-2.local ausgeführt werden kann. Aber es ist ziemlich klobig.

Eine bessere Lösung wäre, die Hosts des Playbooks mithilfe einer Variablen zu definieren und dann eine bestimmte Hostadresse über --extra-vars zu übergeben:

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

Spielbuch ausführen:

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

Wenn {{ target }} nicht definiert ist, macht das Playbook nichts. Eine Gruppe aus der hosts-Datei kann bei Bedarf auch durchgereicht werden. Insgesamt scheint dies eine viel sicherere Möglichkeit zu sein, ein potenziell zerstörerisches Spielbuch zu erstellen.

Playbook für einen einzelnen Host:

$ 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

Playbook mit einer Gruppe von Gastgebern:

$ 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

Vergessen, Hosts zu definieren, ist sicher!

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

playbook: user.yml

  play #1 ({{target}}): Host count=0
175
joemaller

Es gibt auch einen kleinen Trick, mit dem Sie einen einzelnen Host in der Befehlszeile (oder mehrere Hosts, denke ich) ohne Zwischenbestand angeben können:

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

Beachten Sie das Komma (, ) am Ende; Dies zeigt an, dass es sich um eine Liste handelt, nicht um eine Datei.

Dies schützt Sie jedoch nicht, wenn Sie versehentlich eine echte Inventardatei übergeben. Daher ist dies möglicherweise keine gute Lösung für dieses spezielle Problem. Aber es ist ein praktischer Trick!

145
Tybstar

Dieser Ansatz wird beendet, wenn mehr als ein einzelner Host bereitgestellt wird, indem die Variable play_hosts geprüft wird. Das Fail-Modul wird zum Beenden verwendet, wenn die einzelne Host-Bedingung nicht erfüllt ist. Die folgenden Beispiele verwenden eine hosts-Datei mit zwei hosts alice und bob.

user.yml (playbook)

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

Playbook ohne Host-Filter ausführen

$ 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

Playbook auf einem einzigen Host ausführen

$ 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!"
}
69

Es gibt IMHO einen bequemeren Weg. Sie können den Benutzer zwar interaktiv auffordern, die Maschine (n), auf die er das Playbook anwenden möchte, dank vars_Prompt:

---

- hosts: "{{ hosts }}"
  vars_Prompt:
    - name: "hosts"
      Prompt: "Which hosts would you like to setup?"
      private: no
  tasks:
    […]
21
Buzut

Um die Antwort von joemailer zu erweitern, möchten Sie, wenn Sie die Möglichkeit haben, mit einer Musterabgleichung eine beliebige Teilmenge von Remotecomputern abzugleichen (genau wie mit dem Befehl ansible), aber dennoch das Playbook auf allen Rechnern versehentlich ausführen möchten ist was ich mir ausgedacht habe:

Gleiches Spielbuch wie in der anderen Antwort:

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

Lass uns die folgenden Hosts haben:

iMac-10.local
iMac-11.local
iMac-22.local

Um den Befehl auf allen Geräten auszuführen, müssen Sie die Zielvariable explizit auf "all" setzen.

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

Und um es auf ein bestimmtes Muster zu beschränken, können Sie target=pattern_here einstellen.

oder alternativ können Sie target=all verlassen und das --limit-Argument anhängen, zB:

--limit iMac-1*

dh . ansible-playbook user.yml --extra-vars "target=all" --limit iMac-1* --list-hosts

was in ... resultiert:

playbook: user.yml

  play #1 (office): Host count=2
    iMac-10.local
    iMac-11.local
16
deadbeef404

AWS-Benutzer, die das EC2 External Inventory Script verwenden, können einfach nach Instanz-ID filtern:

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

Dies funktioniert, weil das Inventarskript Standardgruppen erstellt .

7
Frank

Seit Version 1.7 hat ansible die Option run_once . Der Abschnitt enthält auch einige Diskussionen zu verschiedenen anderen Techniken.

5
Berend de Boer

Wir haben einige generische Spielbücher, die von einer großen Anzahl von Teams verwendet werden können. Wir haben auch umgebungsspezifische Inventardateien, die mehrere Gruppendeklarationen enthalten.

Um jemanden dazu zu bringen, ein Playbook anzurufen, um eine Gruppe anzugeben, für die er ausgeführt werden soll, wird ein Dummy-Eintrag oben im Playbook eingefügt:

[ansible-dummy-group]
dummy-server

Wir fügen dann die folgende Prüfung als ersten Schritt in das gemeinsam genutzte Playbook ein:

- 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'

Wenn der Dummy-Server in der Liste der Hosts angezeigt wird, für die dieses Playbook geplant ist (Ansible_play_batch), hat der Aufrufer keine Gruppe angegeben, und die Playbook-Ausführung schlägt fehl.

2
mcdowellstl

Ich verstehe wirklich nicht, wie kompliziert alle Antworten sind. Der Weg dahin ist einfach:

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

Im Prüfmodus können Sie im Trockenlauf laufen, ohne Änderungen vorzunehmen.

1
knocte

Ich habe ein Wrapper-Skript namens Provision, das Sie dazu zwingt, das Ziel auszuwählen, sodass ich es nicht anderswo behandeln muss.

Für diejenigen, die neugierig sind, verwende ich ENV-Variablen für Optionen, die von meiner Vagrant-Datei verwendet werden (indem das entsprechende Argument für Cloud-Systeme hinzugefügt wird), und ich lasse den Rest der betreffenden Attribute durch. Beim Erstellen und Bereitstellen von mehr als 10 Servern auf einmal füge ich einen automatischen Wiederholungsversuch auf ausgefallenen Servern hinzu (solange Fortschritte gemacht werden - ich habe festgestellt, dass beim Erstellen von etwa 100 Servern auf einmal ein paar Server beim ersten Mal ausfallen ). 

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
iheggie

Dies ist etwas schwieriger, wenn Sie eine lokale Verbindung verwenden möchten. Dies sollte jedoch in Ordnung sein, wenn Sie eine Variable für die Einstellung hosts verwenden und in der hosts-Datei einen speziellen Eintrag für localhost erstellen.

In (allen) Playbooks ist die Zeile hosts: auf Folgendes eingestellt:

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

Fügen Sie in der Bestands-Hostdatei einen Eintrag für den localhost hinzu, der die Verbindung als lokal definiert:

[localhost]
127.0.0.1  ansible_connection=local

Führen Sie dann in der Befehlszeile Befehle aus, um das Ziel explizit festzulegen - zum Beispiel:

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

Dies funktioniert auch bei der Verwendung von Ansible-Pull:

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

Wenn Sie vergessen, die Variable in der Befehlszeile zu setzen, wird der Befehl sicher ausgegeben (sofern Sie keine Hosts-Gruppe mit dem Namen 'no_hosts' erstellt haben!) Mit folgender Warnung:

skipping: no hosts matched

Und wie oben erwähnt, können Sie eine einzelne Maschine als Ziel auswählen (sofern sich diese in Ihrer hosts-Datei befindet) mit:

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

oder eine Gruppe mit etwas wie:

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