Linux Server mit Fabric verwalten

Fabric ist eine Python Bibliothek mit der Shell Befehle remote über SSH ausgeführt werden können.
Für die Implementierung des SSH-Protokolls wird automatisch Paramiko mit installiert.

Fabric zählt zu den Deployment Tools wie z.B.: Ansible, Chef, Puppet, SaltStack, etc.
Wer Python spricht, ist hier ganz weit vorne. (Ich kann’s leider nicht, geht aber auch ohne.)

Fabric ermöglicht es, mit nur einem Befehl, auf mehreren Servern Abläufe zu automatisieren, wie z.B.:

  • Updates installieren
  • Software installieren
  • Dateien hoch- und runterladen
  • Skripte ausführen
  • Komplexe Umgebungen aufsetzen

Auf den Gegenstellen sollte ein separater Benutzer mit sudo Berechtigungen existieren oder ggf. angelegt werden.

# sudo installieren
$ apt install sudo

# Benutzer anlegen
$ adduser username

# den gewünschten user in die Gruppe sudo aufnehmen
$ usermod -a -G sudo username

Will man nicht jedesmal das sudo Passwort eingeben, gibt man dem Benutzer die Berechtigung sudo ohne Passwort ausführen zu dürfen.

# sudo ohne Passwort, die /etc/sudoers editiert man mit
$ visudo

# am Ende der Datei den Eintrag hinzufügen
username ALL=(ALL) NOPASSWD:ALL

Fabric installieren

Über die Paketverwaltung ist Fabric schnell installiert. (Debian Buster kommt mit Fabric 1.14.0 und Paramiko 2.4.2)
Läuft auch, Paramiko gibt aber einige CryptographyDeprecationWarning Meldungen aus. (nicht schön)

$ fab cmd:"uptime"
[jack@server01] Executing task 'cmd'
[jack@server02] Executing task 'cmd'
[jack@server01] sudo: uptime
[jack@server02] sudo: uptime
/usr/lib/python2.7/dist-packages/paramiko/ecdsakey.py:164: CryptographyDeprecationWarning: \
  Support for unsafe construction of public numbers from encoded data will be removed in a future version. Please use EllipticCurvePublicKey.from_encoded_point
  self.ecdsa_curve.curve_class(), pointinfo
/usr/lib/python2.7/dist-packages/paramiko/kex_ecdh_nist.py:39: CryptographyDeprecationWarning: \
  encode_point has been deprecated on EllipticCurvePublicNumbers and will be removed in a future version. Please use EllipticCurvePublicKey.public_bytes to obtain both compressed and uncompressed 
  point encoding.
  m.add_string(self.Q_C.public_numbers().encode_point())

--- SNIP ---

Das lässt sich durch eine aktuellere Paramiko Version beheben. Dazu installiere ich Fabric 1 mit der Paketverwaltung von Python. (pip)

$ apt install --no-install-recommends python-pip
$ pip install setuptools
$ pip install 'fabric<2.0'
Successfully installed fabric-1.14.1 paramiko-2.6.0

Fabfile (einfach)

Fabric sucht nach einer fabfile.py im aktuellen Verzeichnis. Die Datei mit folgendem Python Code erstellen. (einfaches Beispiel)

from fabric.api import *

env.hosts = [
     'jack@server01',
     'jack@server02',
     'jack@server03',
]

# password for ssh login (NOT RECOMMENDED)
# env.password = 'password-for-jack'

@parallel
def cmd(command):
        sudo(command)

Damit kann jetzt schon jeder Befehl, mit nur einem Kommando, auf allen eingetragenen Hosts ausgeführt werden.

$ fab cmd:"uptime"
[jack@server01] Executing task 'cmd'
[jack@server02] Executing task 'cmd'
[jack@server03] Executing task 'cmd'
[jack@server01] sudo: uptime
[jack@server02] sudo: uptime
[jack@server03] sudo: uptime
[jack@server01] out: sudo password:
[jack@server01] out:  10:04:12 up 14 min,  1 user,  load average: 0.62, 0.60, 0.69
[jack@server01] out: 
[jack@server02] out: sudo password:
[jack@server02] out:  10:10:48 up 10 min,  1 user,  load average: 0.65, 0.60, 0.65
[jack@server02] out:
[jack@server03] out: sudo password:
[jack@server03] out:  17:40:37 up 23 min,  1 user,  load average: 0.77, 0.65, 0.84
[jack@server03] out: 

Done.
Disconnecting from jack@server02... done.
Disconnecting from jack@server03... done.
Disconnecting from jack@server01... done.

Fabfile (erweitert)

Mit roledefs kann man Servergruppen und mit @task und def einzelnen Aufgabengruppen definieren.

from fabric.api import *

# clear screen
import os
os.system('clear')

# display message 
print("  _____     _          _      ")
print(" |  ___|_ _| |__  _ __(_) ___ ")
print(" | |_ / _` | '_ \| '__| |/ __|")
print(" |  _| (_| | |_) | |  | | (__ ")
print(" |_|  \__,_|_.__/|_|  |_|\___|")
print("                              ")        

# group definitions
env.roledefs = {
'raspis':  ['pi@pi01', 'pi@pi02', 'pi@pi03', 'pi@pi04'],
'proxmox': ['root@pve01', 'root@pve02'],
'server':  ['fab@db-srv01',
            'fab@web-srv01',
            'fab@web-srv02',
            'fab@mail-srv01',
            'fab@dns-srv01',
           ],
}

# some global envs
env.colorize_errors = True

@task
# run any command, cmd:"command"
def cmd(command):
    run(command)
   
@task
# update system
def apt_update():
    run('sudo apt-get update && sudo apt-get upgrade -y')

@task
# get uptime
def uptime():
    run('uptime')

@task
# get os version
def os_version():
    run('lsb_release -d')

@task
# upload a file
def deploy_motd():
    put('/etc/update-motd.d/00-server-motd', '/etc/update-motd.d/')

@task
# install a deb package
def deploy_webmin():
    run('wget http://prdownloads.sourceforge.net/webadmin/webmin_1.941_all.deb')
    run('sudo dpkg -i ~/webmin_1.941_all.deb')  
    run('rm ~/webmin_1.941_all.deb')

Verfügbare Kommandos (Aufgabengruppen) des fabfiles ausgeben.

$ fab -l
  _____     _          _      
 |  ___|_ _| |__  _ __(_) ___ 
 | |_ / _` | '_ \| '__| |/ __|
 |  _| (_| | |_) | |  | | (__ 
 |_|  \__,_|_.__/|_|  |_|\___|
                              
Available commands:
    apt_update
    cmd
    deploy_motd
    deploy_webmin
    uptime
    os_version

Von allen Proxmox Servern die PVE Version ausgeben.

$ fab -R proxmox cmd:"pveversion"
  _____     _          _      
 |  ___|_ _| |__  _ __(_) ___ 
 | |_ / _` | '_ \| '__| |/ __|
 |  _| (_| | |_) | |  | | (__ 
 |_|  \__,_|_.__/|_|  |_|\___|
                              
[root@pve01] Executing task 'cmd'
[root@pve01] run: pveversion
[root@pve01] Login password for 'root': 
[root@pve01] out: pve-manager/6.1-3/37248ce6 (running kernel: 5.3.13-1-pve)
[root@pve01] out: 

[root@pve02] Executing task 'cmd'
[root@pve02] run: pveversion
[root@pve02] out: pve-manager/6.1-3/37248ce6 (running kernel: 5.3.13-1-pve)
[root@pve02] out: 

Done.
Disconnecting from pve02... done.
Disconnecting from pve01... done.

Von allen Raspberries die OS Version ausgeben.

 $ fab -R raspis os_version
  _____     _          _      
 |  ___|_ _| |__  _ __(_) ___ 
 | |_ / _` | '_ \| '__| |/ __|
 |  _| (_| | |_) | |  | | (__ 
 |_|  \__,_|_.__/|_|  |_|\___|
                              
[pi@pi01] Executing task 'os_version'
[pi@pi01] run: lsb_release -d
[pi@pi01] Login password for 'pi': 
[pi@pi01] out: Description:        Raspbian GNU/Linux 10 (buster)
[pi@pi01] out: 

[pi@pi02] Executing task 'os_version'
[pi@pi02] run: lsb_release -d
[pi@pi02] out: Description:        Raspbian GNU/Linux 10 (buster)
[pi@pi02] out: 

[pi@pi03] Executing task 'os_version'
[pi@pi03] run: lsb_release -d
[pi@pi03] out: Description:        Raspbian GNU/Linux 10 (buster)
[pi@pi03] out: 

[pi@pi04] Executing task 'os_version'
[pi@pi04] run: lsb_release -d
[pi@pi04] out: Description:        Raspbian GNU/Linux 9.11 (stretch)
[pi@pi04] out: 

Done.
Disconnecting from pi@pi02... done.
Disconnecting from pi@pi04... done.
Disconnecting from pi@pi01... done.
Disconnecting from pi@pi03... done.

Die langen Ausgaben von Fabric können auch etwas unterdrückt werden.

fab --hide=status,running -R raspis os_version
  _____     _          _      
 |  ___|_ _| |__  _ __(_) ___ 
 | |_ / _` | '_ \| '__| |/ __|
 |  _| (_| | |_) | |  | | (__ 
 |_|  \__,_|_.__/|_|  |_|\___|
                              
[pi@pi01] Login password for 'pi': 
[pi@pi01] out: Description:        Raspbian GNU/Linux 10 (buster)
[pi@pi01] out: 
[pi@pi02] out: Description:        Raspbian GNU/Linux 10 (buster)
[pi@pi02] out: 
[pi@pi03] out: Description:        Raspbian GNU/Linux 10 (buster)
[pi@pi03] out: 
[pi@pi04] out: Description:        Raspbian GNU/Linux 9.11 (stretch)
[pi@pi04] out:

Fabric

Geniales Tool! Ich nutze nur einen Bruchteil von dem was Fabric alles leisten kann.
Es erleichtert mir damit aber schon ungemein die Administration und Pflege meiner einzelnen Linux Server.

Schreibe einen Kommentar