Ansible, so einfach!

Konfigurationsmanagement in Rechenzentren ist aus der modernen “DevOps” IT nicht mehr wegzudenken. Puppet, Chef, Salt oder Ansible automatisieren Umgebungen von mittelständischen Unternehmen bis hin zu Weltkonzernen.
Wenn wir die verschiedenen Lösungen betrachten, bedienen sie sich alle einer eigenen Sprache, diese soll möglichst einfach unsere Infrastruktur abbilden. (“infrastructure as a code”)
Da nicht jeder Admin im Tagesgeschäft programmiert, kann so eine Sprache ein Hindernis werden und Arbeitsschritte vielleicht verkomplizieren.
Seit einiger Zeit beschäftige ich mit Ansible, ein Tool welches ohne vorinstallierte Clients arbeitet und eine Konfiurationsprache basierend auf YAML nutzt.
Um Ansible zu nutzen muss lediglich eine SSH Verbindung, ein Benutzer mit Rootrechten und ein Inventarfile bestehen.
Das Sprache im YAML Format ist für jeden leicht lesbar und sofort verständlich.
Ansible kann entweder lokal auf dem Arbeitsrechner oder auf einem sogenannten “Managementnode” über bereitgestellte Pakete installiert werden.
Unter “/etc/ansible/” legen wir nach der Installation zusätzlich ein Inventar an.

$ cat /etc/ansible/hosts
host01.localdomain ansible_ssh_host=10.10.10.11
host02.localdomain ansible_ssh_host=10.10.10.12</pre lang="bash">

Wenn Ansible installiert und ein Inventarfile erstellt wurde, kann die Verbindung zum Server mit dem Modul “ping” getestet werden. Hierbei versucht Ansible den Server per SSH zu erreichen und einzuloggen.

$ ansible host01.localdomain -m ping
host01.localdomain | success >> {
"changed": false,
"ping": "pong"
}</pre lang="bash">

Alternativ kann statt dem Hostalias auch “all” gesetzt werden um alle Hosts aus dem Inventar zu prüfen.

$ ansible all -m ping</pre lang="bash">

Ansible bietet zahlreiche Module mit denen Pakete installiert, Dateien kopiert oder bearbeitet werden können. Hier findet ihr eine Übersicht aller Module
Tasks verwenden diese Module um die Arbeitsschritte in Playbooks oder Rollen auszuführen.
Beispiel eines Playbooks:

$ cat ansible_starter.yml
---
- hosts: all <- Führe die Tasks auf allen Hosts aus
  tasks:
    - name: say hello to everyone <- Name des Tasks
      debug:                      <- Name des Moduls
        msg: "Hello World"        <- Parameter des Moduls

– name: install ntp
yum:
name: ntp
state: installed
</pre lang=”yaml”>

$ ansible-playbook -s ansible_starter.yml
</pre lang="bash">
Diese Task werden der Reihenfolge nach auf dem Zielhost ausgeführt und damit haben wir schon eine kleine Automation geschaffen. Probiert's aus!

Da Ansible im Sturm mein Automationsherz erobern konnte war ich mit meinem Kollegen dieses Jahr auf dem Ansible Fest in London, einen Erfahrungsbericht der Veranstaltung findet ihr hier.

Thilo Wening
Thilo Wening
Senior Consultant

Thilo hat bei NETWAYS mit der Ausbildung zum Fachinformatiker, Schwerpunkt Systemadministration begonnen und unterstützt nun nach erfolgreich bestandener Prüfung tatkräftig die Kollegen im Consulting. In seiner Freizeit ist er athletisch in der Senkrechten unterwegs und stählt seine Muskeln beim Bouldern. Als richtiger Profi macht er das natürlich am liebsten in der Natur und geht nur noch in Ausnahmefällen in die Kletterhalle.

Drei Wege um virtuelle Maschinen zu migrieren

OpenNebulaConf Grafiken 09Neue Storage-Lösungen sprießen wie Tulpen im Frühling aus dem Boden. Jede einzelne ist flexibler, schlanker und hochverfügbarer.
Da kommt meine Cloud ins Spiel, die eigentlich gut läuft aber so ein schnelleres Storage ist eine willkommene Abwechslung.
So ein neues Storage ist schnell aufgesetzt, was uns dann aber vor eine neue Aufgabe stellt,
denn unsere VMs laufen… nur nicht auf unserem hippen Storage.
Nun gibt es diverse Methoden um eine virtuelle Maschine in ein neues Image bzw. neues Storage zu transferieren.
Da haben wir zum einen die altbewährte Methode, mit dem Urgestein aller blockorientierten Kopiervorgänge dd.
Dazu muss die virtuelle Maschine komplett ausgeschaltet sein. Da sich der Zustand der VMs nicht mehr ändert, kann man beruhigt die VM kopieren.
dd if=/path/to/input/file of=/path/to/output/file bs=4096
Zum anderen die Methode ein qcow2 Image in ein Blockdevice zu schreiben.
In Worten gesagt: das Image wird mit “qemu-img convert” in Raw umgewandelt und danach mit dd auf das neue Blockdevice kopiert. (Auch hier sollte die VM nicht mehr laufen!)
qemu-img convert -p -f qcow2 -O raw /path/to/input/file /path/to/outputfile.raw && dd if=/path/to/outputfile.raw of=/path/of/device bs=4M
Da die beiden genannten Arten eine lange Downtime benötigen, sind sie nur für VMs geeignet die nicht zeitkritisch sind.
Ein UNIX System kann mit guten Kenntnissen, mit relativ kurzer Ausfallszeit migriert werden. Ein hilfreiches Werkzeug dabei ist Rsync.
Leider kann ich hierzu kein fixes Beispiel vorzeigen, da die einzelnen Schritte von System zu System unterschiedlich ausfallen.
Die essentiellen Schritte sind:
1. Neues Device in der VM mounten und das gewünschte Filesystem erstellen.
2. Systemverzeichnisse auf dem neuen Device erstellen.
3. Das komplette System mit Rsync auf das neue Device kopieren. Hier muss man natürlich etwas aufpassen und Verzeichnisse wie /proc oder ggf. /mnt exkludieren. Auch auf bind Mounts sollte man achten, damit man Daten nicht ausversehen doppelt kopiert.
4. Die grub.cfg natürlich im neuen /boot Pfad aktualisieren. (grub-install und update-grub sind hierfür hilfreich)
5. Das “alte Device” als read-only einbinden und die neue fstab anpassen.
6. Und last but not least, einen weiteren Rsync in dem die restlichen Files auf das neue Image übertragen werden. (auch hier bitte das Exkludieren von wichtigen Pfaden nicht vergessen. z.B.: /etc/fstab oder auch /boot !!)
Der Vorteil hierbei ist: die Downtime erstreckt sich dabei nur über den zweiten Rsync, bei dem die Festplatte im “read-only” Modus ist.
Habt Ihr weitere coole Möglichkeiten einen VM zu migrieren?
Dann dürft ihr euch in den Kommentaren dazu äußern.
Oder seid Ihr interessiert an dem Thema Cloud und alles was damit zu tun hat? Dann besucht uns einfach auf der OpenNebula Conf 2014

Thilo Wening
Thilo Wening
Senior Consultant

Thilo hat bei NETWAYS mit der Ausbildung zum Fachinformatiker, Schwerpunkt Systemadministration begonnen und unterstützt nun nach erfolgreich bestandener Prüfung tatkräftig die Kollegen im Consulting. In seiner Freizeit ist er athletisch in der Senkrechten unterwegs und stählt seine Muskeln beim Bouldern. Als richtiger Profi macht er das natürlich am liebsten in der Natur und geht nur noch in Ausnahmefällen in die Kletterhalle.

Wenn das MacBook zu heiß ist – cpulimit.sh

Ich mag laute Hardware nicht. Und ich fand es gut, dass mein iBook mit 600MHz PowerPC G3 Prozessor aus dem Jahr 2001 nur im absoluten Notfall den Lüfter eingeschaltet hat. Auch mein MacBook Pro mit 2,4GHz Intel Core 2 Duo Prozessor war im Normalfall nicht zu hören.
Aber mein neues MacBook Pro mit 2,2GHz Intel Core i7 erdreistet sich, bei verschiedenen Gelegenheiten, in den “Jet-mode” zu gehen. Die Ursache ist dann gern mal der Indexer für Spotlight (metadata server – mds) oder ein Video Player (video lan client – vlc). Beide brauchen eigentlich nicht mit voller Power zu laufen um meinen Ansprüchen gerecht zu werden. Ausserdem braucht man meist auch die dedizierte Grafikkarte nicht. Die kann man aber Dank gfxCardStatus einfach abschalten. Achtung, nicht vergessen wieder anzuschalten, wenn man den Beamer dranhängt!
Apple hat leider keine Möglichkeit vorgesehen die CPU zu drosseln um weniger Strom zu verbrauchen und somit den Akku und das Gehör zu schonen. Todtraurig!
Nice ist auch keine Lösung, weil ja dennoch die Power genutzt wird die zur Verfügung steht.
Aber ich habe etwas gefunden was an dieser Stelle weiterhelfen kann: cpulimit. Das ließ sich aber unter Lion nicht compilieren. Es gibt da aber noch diese Variation davon.
An der Shell Variante habe ich ein wenig gefeilt. Nun bekommt man eine Liste der CPU hungrigen Prozesse zur Auswahl und den Erstplatzierten als Vorauswahl.
Das Ergebnis sieht dann so aus:

$ sudo ~/bin/cpulimit.sh
Password:
  This script will throttle a chosen process as you like it.
  Therefore your cpu runs cooler - hopefully.
Chose which process to throttle:
 PPID   PID USER            %CPU %MEM STARTED      TIME     STIME COMMAND
    1    66 root            25,5  5,1 Do08am   73:25.42  32:24.31 mds
  273   436 bschmidt        23,1  0,1 Do08am    1:20.18   0:13.72 Folder Actions Dispatcher
    1 19304 root            15,3  0,1 Sa03pm   62:40.11  51:14.03 activitymonitord
  273 91519 bschmidt        14,6  0,3  7:57pm   0:06.47   0:02.17 mdworker
    1    12 _mdnsresponder  12,6  0,0 Do08am   26:20.00  19:02.96 mDNSResponder
  273 91189 bschmidt        11,6  0,4  7:55pm   0:06.54   0:02.21 mdworker
  273 91520 bschmidt        11,3  0,3  7:57pm   0:06.48   0:02.17 mdworker
  273 91518 bschmidt         9,2  0,3  7:57pm   0:06.36   0:02.14 mdworker
  273 13471 bschmidt         8,7  3,6 Fr02pm  101:01.25  22:25.71 Google Chrome
Which process ID (PID) [guess: 66]?
Chosen:
  PID USER  %CPU %MEM STARTED      TIME COMMAND
   66 root  21,9  5,1 Do08am   73:26.43 /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Support/mds
Sleep time in seconds (e.g 0.5 or 1 …) [default: 0.5]?
Run time in seconds (e.g 0.5 or 1 …) or percent [default: .5000 = 50%]?
OK. I will throttle PID 66 now and dislay processinfo every 20 seconds …
  PID USER  %CPU %MEM STARTED      TIME COMMAND
   66 root  40,5  4,7 Do08am   73:34.02 /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Support/mds
  PID USER  %CPU %MEM STARTED      TIME COMMAND
   66 root  32,7  4,8 Do08am   73:34.91 /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Support/mds
  PID USER  %CPU %MEM STARTED      TIME COMMAND
   66 root   0,0  4,8 Do08am   73:35.15 /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Support/mds
^C
*** Ouch! Stop throtteling of PID 66. Exiting ***

Mit diesem Script ist es ein Leichtes, Prozesse ausser Rand und Band wieder einzufangen. Erstaunlicher Weise sogar den Video Player, wenn man nur die sleep time kurz genug wählt.
Da das Script nicht lang ist, stell ich es hier einfach mal rein:

#! /bin/bash
# Description:
#
# If you want to decrease the CPU demands for an application
# you can use this very simple and ugly "hack".
# I use it when I convert videos on my MacBook Pro
# to prevent it from getting to warm. Even if the CPU is IDLE this hack
# will prevent the application to use the CPU during Sleep Time
# (in contrast to renice/nice commands which will take all IDLE time).
# This means the conversions will take longer time, but I
# don't care because I run it at night.
#
# There is similar c program for Linux called cpulimit, but it wont
# compile on my Mac.
#
# Usage:  sudo ./cpulimit.sh
#
#################################
# config
sleeptime_default=0.5   # in seconds
runtimep_default=50     # in percent (50 = same as sleeptime)
reporttime=30           # report every x seconds while running
# PROCESSLISTformat: pid has to be on the second position
PROCESSLISTformat="ppid,pid,user,%cpu,%mem,start,cputime,stime,command"
#PROCESSLISTformat="ppid,pid,user,%cpu,%mem,start,cputime,stime,rss,vsz,cpu,re,wq,wqr,stat,nsigs,command"
#################################
# dont change anything below here
pid=""
scriptuser=$(id -u)
# run if user hits control-c
control_c()
{
  echo ""
  if [ "$pid" != "" ]; then
    echo -en "\n*** Ouch! Stop throtteling of PID $pid. Exiting ***\n"
    kill -SIGCONT $pid
  fi
  echo ""
  exit $?
}
# trap keyboard interrupt (control-c)
trap control_c SIGINT
pidstring()
{
  # takes pid as argument
  ps -p $1 -w -o pid,user,%cpu,%mem,start,cputime,command 2>/dev/null
}
isnumber()
{
  if [[ "$1" =~ ^[0-9]*([.][0-9]+)?$ ]] ; then
    return 0
  else
    return 1
  fi
}
#################################
# main
cat << EOF
  This script will throttle a chosen process as you like it.
  Therefore your cpu runs cooler - hopefully.
EOF
if [ "$scriptuser" != "0" ]; then
cat << EOF
  You're not root!
  If you want to controll processes that you dont own,
  please run via sudo.
EOF
fi
PIDSTRING=""
until [ "$PIDSTRING" != "" ]; do
  #PROCESSLIST=$(ps -r -A -f -S | head)
  if [ "$scriptuser" != "0" ]; then
    PROCESSLIST=$(ps -r -u $scriptuser -S -c -o $PROCESSLISTformat 2>/dev/null)
  else
    PROCESSLIST=$(ps -r -A -S -c -o $PROCESSLISTformat 2>/dev/null)
  fi
  if [ "$PROCESSLIST" = "" ]; then
    echo -en "\n*** Sorry, ps dont work as expected on $(uname). Exiting ***\n\n"
    exit 1
  else
    PROCESSLIST=$(echo "$PROCESSLIST" | head)
  fi
  echo -en "\nChose which process to throttle:\n$PROCESSLIST\n"
  PID_GUESS=$(echo "$PROCESSLIST" | head -2 | tail -1 | awk '{print $2}')
  echo -n "Which process ID (PID) [guess: $PID_GUESS]? "
  read pid
  if [ "$pid" = "" ]; then
      pid=$PID_GUESS
  fi
  # test if $pid is valid
  PIDSTRING=$(pidstring $pid)
  if [ "$?" -eq "0"  ]; then
    echo -en "\nChosen:\n$PIDSTRING\n"
  else
    echo -en "\n$pid is not a valid PID for a running process.\n"
    pid=""
  fi
  echo -en "\n"
done
sleeptime=""
until [ "$sleeptime" != "" ]; do
  echo -n "Sleep time in seconds (e.g 0.5 or 1 …) [default: $sleeptime_default]? "
  read sleeptime
  if [ "$sleeptime" = "" ]; then
    sleeptime=$sleeptime_default
  fi
  isnumber $sleeptime || sleeptime=""
done
#echo "sleeptime $sleeptime"
runtime=""
until [ "$runtime" != "" ]; do
  runtime_default=$(echo "scale=4;$sleeptime*$runtimep_default/(100-$runtimep_default)"|bc)
  echo -n "Run time in seconds (e.g 0.5 or 1 …) or percent [default: $runtime_default = $runtimep_default%]? "
  read runtime
  if [[ "$runtime" =~ ^([0-9]*([.][0-9]+)?)%$ ]] ; then
    runtimep_default=${BASH_REMATCH[1]}
  fi
  if [ "$runtime" = "" ]; then
    runtime=$runtime_default
  fi
  isnumber $runtime || runtime=""
done
#echo "runtime $runtime"
# now begin throttle
throttletime=1000000
looptime=$(awk "BEGIN { printf \"%.0f\\n\", ($sleeptime+$runtime)*100 }")
echo "OK. I will throttle PID $pid now and dislay processinfo every $reporttime seconds … "
((reporttime=$reporttime*100))
while true
do
  if [ $throttletime -ge 500 ]; then
    throttletime=0
    PIDSTRING=$(pidstring $pid)
    echo "$PIDSTRING"
  fi
  kill -SIGSTOP $pid || control_c
  sleep $sleeptime
  kill -SIGCONT $pid || control_c
  sleep $runtime
  throttletime=$(($looptime+$throttletime))
done

Unix Cheatsheets

Selbst der erfahrene Unix System Administrator muss hin und wieder mal was nachsehen. Normalerweise bieten sich da die entsprechenden Man Pages oder Google an. Aber was macht man, wenn man gar nicht weiss nach welchem Kommando man eigentlich suchen soll? Die Unix Toolbox ist eine sehr umfangreiche Referenz, die alle wichtigen Kommandos auflistet. Ohne lange Erklärungen, denn die Optionen jeden Befehls kann man ja dann später in den Man Pages nachlesen. Ein interessantes Konzept verfolgt Rosetta Stone for Unix. Auf dieser Website kann man sich die Befehle für verschiedene Unix Varianten “übersetzten” lassen. Zur Auswahl stehen: AIX, A/UX, DG/UX, FreeBSD, HP-UX, IRIX, Linux, Mac OS X, NCR Unix, NetBSD, OpenBSD, Reliant, SCO OpenServer, Solaris, SunOS 4, Tru64, Ultrix und UNICOS. Das könnte helfen, wenn man sich mal auf einer weniger verbreiteten Plattform bewegen muss.

Julian Hein
Julian Hein
Executive Chairman

Julian ist Gründer und Eigentümer der NETWAYS Gruppe und kümmert sich um die strategische Ausrichtung des Unternehmens. Neben seinem technischen und betriebswirtschaftlichen Background ist Julian häufig auch kreativer Kopf und Namensgeber, beispielsweise auch für Icinga. Darüber hinaus ist er als CPO (Chief Plugin Officer) auch für die konzernweite Pluginstrategie verantwortlich und stösst regelmässig auf technische Herausforderungen, die sonst noch kein Mensch zuvor gesehen hat.