EXT4 Dateisystem im laufenden Betrieb vergrößern

Das EXT4 Dateisystem kann im laufendem Betrieb ohne Neustart vergrößert werden. In diesem Beispiel dient als virtuelle Maschine auf einem VMWare Hypervisor als Basis.

Das Basis-Image hat eine 30GB Partition, die in diesem Beispiel voll ist:

~$ df -h /
Filesystem          Size  Used Avail Use% Mounted on
/dev/sda1            29G   28G     0 100% /

Das Betriebssystem hat die Vergrößerung der Festplatte (sda) bereits bemerkt, die Partition (sda1) ist aber noch 30GB groß:

~$ cat /proc/partitions
major minor #blocks name
11 0 1048575 sr0
8 0 104857600 sda
8 1 30718976 sda1

Um die Partition zu vergrößern, nutze ich das Werkzeug fdisk und lösche damit die 30GB große Partition um sie direkt im Anschluss wieder als 100GB große Partition anzulegen:

~$ fdisk /dev/sda
Welcome to fdisk (util-linux 2.23.2).

Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help): p

Disk /dev/sda: 107.4 GB, 107374182400 bytes, 209715200 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x000b8bb4

Device Boot Start End Blocks Id System
/dev/sda1 * 2048 61439999 30718976 83 Linux

Command (m for help): d
Selected partition 1
Partition 1 is deleted

Command (m for help): n
Partition type:
p primary (0 primary, 0 extended, 4 free)
e extended
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-209715199, default 2048):
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-209715199, default 209715199):
Using default value 209715199
Partition 1 of type Linux and of size 100 GiB is set

Command (m for help): p

Disk /dev/sda: 107.4 GB, 107374182400 bytes, 209715200 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x000b8bb4

Device Boot Start End Blocks Id System
/dev/sda1 2048 209715199 104856576 83 Linux

Command (m for help): a
Selected partition 1

Command (m for help): p

Disk /dev/sda: 107.4 GB, 107374182400 bytes, 209715200 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x000b8bb4

Device Boot Start End Blocks Id System
/dev/sda1 * 2048 209715199 104856576 83 Linux

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 16: Device or resource busy.
The kernel still uses the old table. The new table will be used at
the next reboot or after you run partprobe(8) or kpartx(8)
Syncing disks.

Fdisk versucht zwar, die Partitionstabelle neu zu laden, dies schlägt jedoch fehl. Hier schafft partx Abhilfe:

~$ partx -u /dev/sda1

Die Partitionstabelle ist aktualisiert und mittels resize2fs kann ich nun auch das Dateisystem vergrößern:

~$ resize2fs /dev/sda1
resize2fs 1.42.9 (28-Dec-2013)
Filesystem at /dev/sda1 is mounted on /; on-line resizing required
old_desc_blocks = 4, new_desc_blocks = 13
The filesystem on /dev/sda1 is now 26214144 blocks long.

Das Dateisystem ist jetzt ohne Neustart des Systems vergrößert:

~$ df -h /
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 99G 28G 67G 30% /

Unnützes nützlich machen: Bash Funktion zur Überprüfung der Verfügbarkeit von SSH

Folgende Funktion überprüft, ob eine gegebene IP und passender SSH-Port online sind und liefert animierte Statusmeldungen, falls IP oder Port nicht erreichbar sind:

function available () {
        host=${1}
        port=${2:-22} # take given port or default 22

        # check if host is dead (-c = count, -W = timeout, -q = quiet)
        if ! /bin/ping -c1 -W1 -q ${host} 2>&1 &>/dev/null; then
                # if so, clear line and print animated status
                for num in $(echo "52 88 124 1 196 1 124 88 52"); do
                        echo -en "\e[38;5;${num}mwaiting for host to come online.\e[0m\r"
                        /bin/sleep 0.1
                        /usr/bin/tput el # clear line
                done
                # return 1 in order to exit function
                return 1
        else
                # check if ssh port is closed (-n = numeric [only IP], -z = zero-I/O mode [used for scanning], -w = timeout)
                if ! /bin/nc -nzw2 ${host} ${port}; then
                        # if so, clear line and print animated status
                        for num in $(echo "130 166 172 214 11 214 172 166 130"); do
                                echo -en "\e[38;5;${num}mwaiting for port ${port} to come online.\e[0m\r"
                                /bin/sleep 0.1
                        /usr/bin/tput el # clear line
                done
                # return 1 in order to exit function
                return 1
                fi
        fi
}

Diese Funktion rufe ich nun beispielsweise in einer Until-Schleife so lang auf, bis IP und Port verfügbar sind, um dann eine bestimmte Aktion auszuführen:

. inc
until available 81.3.9.194 22; do 
        true
done
ssh 81.3.9.194

Die Funktion wird aus der Datei “inc” gesourced und in der Until-Schleife so lang ausgeführt, bis das System pingbar und Port 22 offen ist – anschließend wird eine SSH-Verbindung aufgebaut.

Konsistente MySQL Backups mit MyLVMBackup

mylvmbackup setzt vorraus, dass das Daten-Verzeichnis von MySQL (z.B. /var/lib/mysql) auf einem Logical Volume (LVM) liegt und erstellt Backups, in dem es einen READ LOCK in MySQL ausführt, den Cache auf die Festplatte schreibt und ein Snapshot des Logical Volume erstellt. Dieser Vorgang dauert in der Regel ungefähr eine Sekunde, anschließend läuft der MySQL-Server normal weiter und das Backup kann aus dem Snapshot erstellt werden.

mylvmbackup ist in Debian seit Version 6 (Squeeze) über die Paketverwaltung (http://packages.debian.org/wheezy/mylvmbackup) verfügbar und lässt sich via apt-get oder aptitude installieren:

aptitude install mylvmbackup

Die Konfigurationsdatei ist /etc/mylvmbackup.conf und erfordert individuelle Anpassungen vor der ersten Ausführung:

[mysql]:
user=USER
password=PASSWORD

[lvm]:
vgname=vg01 # folgender Befehl zeigt den richtigen Wert an: /sbin/vgdisplay |awk '/VG Name/ {print $3}'
lvname=MySQL # Logical Volume, auf dem sich die MySQL-Daten befinden
backuplv=Temp # definiert den Namen des Logical Volumes, das mylvmbackup für den Snapshot benutzt
lvsize=50G # definiert die Größe des Logical Volumes (die Größe sollte der des Datenvolumens entsprechen)

[fs]:
xfs=1 # muss aktiviert werden, wenn das Datenvolumen XFS formatiert ist
mountdir=/var/cache/mylvmbackup/mnt/ # definiert den Pfad, in dem das temporäre Logical Volume gemountet wird
backupdir=/backup/ # definiert den Speicherort für das fertige Backup

[logging]:
log_method=console # der Output von mylvmbackup< wird direkt an STDOUT der Console übergeben, alternative Optionen sind "syslog" und "both"

Um regelmäßig Backup zu erstellen, empfielt sich ein Cronjob (z.B. in /etc/cron.d/mylvmbackup):

SHELL=/bin/bash
# m h dom mon dow user command
01 1 * * * root /usr/bin/mylvmbackup --innodb_recover --backuptype=tar &>> /var/log/mylvmbackup.log

Dieser Cronjob würde ein seperates Logfile erstellen, dass man mit Logrotate rotieren lassen kann. Dafür reicht folgende Konfiguration unter "/etc/logrotate.d/":

/var/log/mylvmbackup.log {
      daily
      rotate 7
      missingok
      create 640 root adm
      compress
      sharedscripts
}

Dies sorgt dafür, dass die Logdatei täglich rotiert wird und nach 7 Tagen gelöscht wird.

Bash: Definition einer Funktion anzeigen

Mit dem Befehl “declare -f ” kann man sich den Code einer bestimmten Funktion anzeigen lassen:

10:22 (1) node01:~$ declare -f show_keys
show_keys () 
{ 
    if [ -d ~/.ssh ]; then
        echo -e "\033[3;34m#\tSSH keys:\033[0m";
        sed '/^#/d;s/.*ssh-.*AAAA[^ ]\+ //' ~/.ssh/authorized_keys | while read key; do
            echo -e "\033[3;34m# $key \033[0m";
        done;
    else
        log_msg "no ssh keys" 1;
    fi
}

Mit “declare -F” kann man sich alle momentan deklarierten Funktionen anzeigen lassen, ein einfaches “declare” zeigt neben allen Funktionen auch die Umgebungsvariablen an.

kurz notiert: Standard Munin Graphen für Apache konfigurieren

Das Munin Paket von Debian bringt von Haus aus drei Plugins für Apache mit. Um Zugriffe, Prozesse und Datenvolumen mit Munin festhalten zu können, wird das Apache Status Modul vorrausgesetzt und wie folgt aktiviert:
a2enmod status
Falls das Modul noch nicht aktiv ist, muss die Konfiguration neu eingelesen werden:
/etc/init.d/apache2 reload
Die Plugins werden via Symlink eingebunden…
ln -s /usr/share/munin/plugins/apache_accesses /etc/munin/plugins/
ln -s /usr/share/munin/plugins/apache_processes /etc/munin/plugins/
ln -s /usr/share/munin/plugins/apache_volume /etc/munin/plugins/

…und mit dem folgenden Befehl aktivieren:
dpkg-reconfigure munin-node
Für das “apache_processes” Plugin wird das Perl Modul “LWP::Useragent” (eventuell auch “IO:Socket:SSL”) benötigt und kann wie folgt installiert werden::
aptitude install libwww-perl libio-socket-ssl-perl
Anschließend kann man testen, ob die Plugins funktionieren:
:~$ /usr/share/munin/plugins/apache_processes autoconf
yes

Bei älteren Debian Systemen muss man die Option “ExtendedStatus” in der /etc/apache2/mods-enabled/status.conf noch von Hand nachtragen, in der aktuellen Version ist diese Option per default auf “on”.

Apache_volume-week

Apache_processes-week

Apache_accesses-week

Debian: Boot Messages auf dem Bildschirm belassen

Mit der aktuell von Debian Wheezy gelieferten Version 2.20.1 von util-linux gibt es für getty die Option
–noclear, mit der man das Löschen der Boot Messages in der Console verhindern kann bzw. muss, da das Default-Verhalten “clear” ist:


:~$ man -Pcat getty|grep -A1 noclear
--noclear
Do not clear the screen before prompting for the login name (the screen is normally cleared).

Die Option muss in der /etc/inittab eingetragen werden:
1:2345:respawn:/sbin/getty --noclear 38400 tty1

BTW: Die Farben während der Bootsequenz lassen sich (momenten) wie folgt deaktivieren:
echo "FANCYTTY=0" > /etc/lsb-base-logging.sh

Eventuell wird sich dies noch bis zum Release von Wheezy ändern.

SSH-Login für Fortgeschrittene

Da ich viel mit SSH arbeite und ich auf Automatisierung stehe, sieht mein Login inzwischen so aus:

Statt “ssh root@192.168.50.1” gebe ich nur noch die IP auf der Kommandozeile ein:

local:~$ 192.168.50.1
Last login: Fri Mar 30 16:30:42 2012
16:54 node01:~#

Dies funktioniert durch editieren der Funktion “command-not-found”:

command_not_found_handle () {
ssh $@
}

Da mein System den Befehl “192.168.50.1” nicht kennt, wird die Funktion command_not_found_handle ausgeführt und somit “ssh 192.168.50.1” (Eigentlich führe ich in der command-not-found-Funktion “$HOME/scripts/expect.sh” statt “ssh” aus – “ssh” dient hier nur zum Verständnis).

In meiner ~/.ssh/config habe ich folgende Optionen:

User root
Host *
ForwardAgent yes
RemoteForward 55557 127.0.0.1:80

Dadurch sieht mein wirklicher Befehl so aus:

ssh -R 55557:127.0.0.1:80 root@192.168.50.1

Die RemoteForward-Option baut einen SSH-Tunnel zu node01 auf und ermöglicht mir, über Port 55557 auf Port 80 meines lokalen Systems zugreifen.

Diesen SSH-Tunnel nutze ich, um diverse Aliase und Funktionen zu laden, sowie bestimmte Befehle direkt nach dem Login auszuführen (z.B. eine Überprüfung auf volle Partitionen, wie im Screenshot zu sehen ist).

Damit dies automatisch direkt nach dem Login passiert, nutze ich expect:

Expect is a tool for automating interactive applications according to a script. Following the script, Expect knows what can be expected from a program and what the correct response should be. Expect is also
useful for testing these same applications. And by adding Tk, you can also wrap interactive applications in X11 GUIs. An interpreted language provides branching and high-level control structures to direct the
dialogue. In addition, the user can take control and interact directly when desired, afterward returning control to the script.

local:~$ cat $HOME/scripts/expect.sh
#!/usr/bin/expect

set cmd1 {eval $(wget http://127.0.0.1:55557/screen.html -qO-); hide}
set cmd2 {eval $(wget http://127.0.0.1:55557/ -qO-); hide}

trap {
set cols [stty columns]
set rows [stty rows]
stty rows $rows columns $cols < $spawn_out(slave,name)
} WINCH

spawn ssh $argv
expect {

“*assword:” {
interact -o “:~#” return
send “$cmd1\r”
send “$cmd2\r”

}

“:~#” {
send “$cmd1\r”
send “$cmd2\r”

}

}
interact

expect automatisiert den Login und führt die beiden definierten Kommandos “cmd1” und “cmd2” aus.

Als erstes erstelle ich durch “eval $(wget http://127.0.0.1:55557/screen.html -qO-)” eine Screen-Session mit hardstatus Zeile:

local:~$ cat /var/www/screen.html
hide () { history -d $(history | tail -1 | awk '{print $1}'); } ;
if [ -x /usr/bin/screen ]; then
echo 'termcapinfo xterm ti@:te@' > /tmp/.sre-screenrc;
unset TTY;
export TTY=$(tty|awk -F/ '{print $4}');
/usr/bin/screen -c /tmp/.sre-screenrc -d -m -S TTY${TTY}.sre;
/usr/bin/screen -r TTY${TTY}.sre -X backtick 1 0 0 echo $(hostname -f) is $(cat /etc/issue.net) with $(/bin/grep -c processor /proc/cpuinfo) CPU and $(free -m|awk '/Mem/ {print $2}')M RAM \| $(wget -q http://icanhazip.com -O -);
/usr/bin/screen -r TTY${TTY}.sre -X hardstatus on;
/usr/bin/screen -r TTY${TTY}.sre -X caption always;
/usr/bin/screen -r TTY${TTY}.sre -X defscrollback 5000;
/usr/bin/screen -r TTY${TTY}.sre -X vbell off;
/usr/bin/screen -r TTY${TTY}.sre -X caption string '%{=b dk}[ %1` ] %=';
hide;
/usr/bin/screen -r TTY${TTY}.sre;
/bin/rm -f /tmp/.sre-screenrc;
exit;
fi;

Im zweiten Schritt setze ich innerhalb der Screen-Session mit dem Befehl “eval $(wget http://127.0.0.1:55557/ -qO-)” weitere Funktionen und Aliase:

local:~$ cat /var/www/index.html
hide () { history -d $(history | tail -1 | awk '{print $1}'); } ;
alias grep='grep -ir --color';
PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"';
PS1="\[\033[1;34m\]\A \h:\w$\[\033[0m\] ";
[...]

Beispiele für at jobs

Da ich “at” als sinnvoll empfinde, es aber nicht all zu oft benutze, vergesse ich immer wieder die Syntax… deshalb hier nun die vereinfachte Syntax und anschließend zwei Beispiele für den Einsatz von at mit genauer und relativer Zeitangabe:

Syntax:
genaue Zeitangabe: at time date
relative Zeitangabe: at now + COUNT UNIT

Beispiel 1)
Mittels “Here Strings” (bash manual) wird der Befehl “touch foo” via StdIn an at übergeben und um 12:00Uhr ausgeführt:

at 12:00 <<<"touch foo"

Beispiel 2)
In ungefähr 5 Minuten wird das Script test.sh ausgeführt (Ausführungszeitpunkt ist immer eine volle Minute):

at now +5min -f test.sh

Bleibt nur noch zu erwähnen, dass mit "atq" bevorstehende at jobs angezeigt werden und man mit "atrm " bevorstehende jobs löschen kann.

screen: Optionen ohne .screenrc übergeben

Um beispielsweise auf einem fremden System screen mit seinen persönlichen Optionen nutzen zu können, ohne eine screenrc-Datei zu erstellen, kann man die “-X” Option nutzen:

screen -d -m -S sre
screen -r sre -X backtick 1 0 0 /bin/hostname -f
screen -r sre -X backtick 2 0 0 grep -c processor /proc/cpuinfo
screen -r sre -X backtick 3 1 1 /usr/bin/uptime
screen -r sre -X hardstatus on
screen -r sre -X caption always
screen -r sre -X caption string '%{=b dk}[ %{R}%1` %{=b dk}] | %{=b dk}[ %{R}%2` cores %{=b dk}] %= [%{R}%3` %{=b dk}]'
screen -r sre -X vbell off
screen -r sre

Ich nutze diese Befehle in einem expect-script, dass nach dem Login automatisch diese Befehle ausführt.

Debian: Upgrade auf nächste Version

Debian 7 “Wheezy” -> Debian 8 “Jessie”

aptitude update && aptitude -y safe-upgrade && sed -i 's/wheezy/jessie/g' /etc/apt/sources.list && dpkg --clear-avail && aptitude update && aptitude -y install apt dpkg aptitude && aptitude -y dist-upgrade

Debian 6 “Squeeze” -> Debian 7 “Wheezy”

aptitude update && aptitude -y safe-upgrade && sed -i 's/squeeze/wheezy/g' /etc/apt/sources.list && dpkg --clear-avail && aptitude update && aptitude -y install apt dpkg aptitude && aptitude -y dist-upgrade

Debian 5 “Lenny” -> Debian 6 “Squeeze”

aptitude update && aptitude -y safe-upgrade && sed -i 's/lenny/squeeze/g' /etc/apt/sources.list && dpkg --clear-avail && aptitude update && aptitude -y install apt dpkg aptitude && aptitude -y full-upgrade