Debian auf der DiskStation

Aus

Anleitung zur Installation von Debian auf der Synology DiskStation (Hier: ARMEL auf DS210j/DS211+)


Einleitung

Ich übernehme keine Haftung/Garantie für diese Anleitung. Die Gefahr, etwas zu zerstören, ist bei einem chroot aber seeeehr klein.

Vorbereitung

Man braucht einen Debian-Rechner, auf dem man die Pakete herunterlädt. Auf diesem führt man diese Befehle aus:

apt-get install debootstrap -y
apt-get clean
debootstrap --foreign --arch armel squeeze debian "http://ftp.de.debian.org/debian"

Bitte armel durch die richtige Architektur der DS ersetzen. Dieses Beispiel funktioniert für DS210j/211+ und wahrscheinlich noch viele weitere (110j, 410j etc).

Sobald der Vorgang abgeschlossen ist, muss das Archiv gepackt werden. Das geht mit diesem Befehl:

tar -czf debian.tar.gz debian

Jetzt nur noch das tar.gz auf die Synology kopieren auf einem Volume (z.B. /volume1/)

Weiter auf der Synology

Entpacken:

gunzip debian.tar.gz
tar -xvf debian.tar
cd debian

proc mounten

mount -t proc none ./proc

chrooten

chroot ./ /bin/bash

System installieren

/debootstrap/debootstrap --second-stage

Hostname anpassen

echo "diskstation" >/etc/hostname

Hosts kopieren

exit
cp /etc/hosts ./etc/hosts

erneut chrooten

mount -t proc none ./proc
chroot ./ /bin/bash

apt-get einrichten

nano /etc/apt/sources.list

Folgendes einfügen:

deb http://ftp2.de.debian.org/debian/ squeeze main
deb-src http://ftp2.de.debian.org/debian/ squeeze main
deb http://security.debian.org squeeze/updates main

Mit CTRL+X speichern und verlassen

System aktualisieren

apt-get update
apt-get upgrade
apt-get dist-upgrade

Nun haben wir ein aktuelles Debian Squeeze auf der Synology. Um in dieses zu wechseln, einfach nach /volume1/debian wechseln und ein

mount -t proc none ./proc
chroot ./ /bin/bash

absetzen. Falls eine Meldung kommt wie proc ist schon gemountet, einfach ignorieren. Zum Verlassen einfach exit eingeben.

Viel Spaß

Anpassungen am System der Firmware

Startscripte (basic)

Der chroot kann seine Dienste nicht selbständig starten. Das muss von ausserhalb, also der Firmware der DS passieren. Dazu kann man eigene Startscripte erstellen und diese dann entweder in /usr/syno/etc.defaults/rc.d oder /opt/etc/init.d platzieren. Hier mal ein Beispiel eines Startscriptes für den Apache des Debian

#!/bin/sh

if [ "$*" = 'start' ] ; then
 chroot /volume1/debian /etc/init.d/apache2 start
else
 chroot /volume1/debian /etc/init.d/apache2 stop
fi

dabei ist /volume1/debian der Pfad zum chroot des Debian Systems und das Kommando dahinter wird dann **innerhalb des chroots ausgeführt**.

Wichtig wäre es noch, dass man im chroot gesetzte mounts beim Shutdown ebenfalls entfernt, sonst bleibt die DS hängen

#!/bin/sh

if [ "$*" = 'start' ] ; then
 mount -t proc none /volume1/debian/proc
 chroot /volume1/debian /etc/init.d/apache2 start
else
 chroot /volume1/debian /etc/init.d/apache2 stop
 umount /volume1/debian/proc
fi

wichtig ist folgender Grundsatz: Beim Starten immer erst die mounts und dann die Prozesse starten und beim Beenden erst die Prozesse killen und dann die mounts entfernen.

Startscripte (erweitert)

Viele Prozesse starten

Sobald man eine bestimmte Anzahl Prozesse starten will tippt man sich einen Wolf, wenn man jeden Prozess einzeln stop und starten will. Dazu bietet sich dann die for-Schleife an

#!/bin/sh

case "$*" in
 'start')
    for i in cron apache2 postfix dovecot dnsmasq lighttpd webmin ; do
     chroot /volume1/debian /etc/init.d/$i start
    done
 ;;
 'stop')
    for i in cron apache2 postfix dovecot dnsmasq lighttpd webmin ; do
     chroot /volume1/debian /etc/init.d/$i stop
    done
 ;;
 *)
    echo 'Usage stop|start'
 ;;
esac

SSH sauber beenden

Wenn man sich im chroot einen ssh Server installiert und diesen auch nutzt gibt es zwei wichtige Punkte für den Stop-Teil des Scriptes:

1. SSH muss komplett beendet werden
2. alle Loginshells müssen beendet werden
1) ist relativ einfach. Dazu muss man einfach das Startscript anpassen
2) wird oft vergessen :-)

Solange noch eine Loginshell aktiv ist - und mit kill sshd werden Loginshells NICHT beendet - kann man den pts mount nicht entfernen. Damit würde der reboot hängen bleiben. Damit man die Loginshells alle erwischt, ist es nützlich zu wissen, dass der chroot per default bash als Login Shell nutzt und die Firmware aber sh resp ash. Damit kann man relativ einfach ein Script schreiben, welches alle Bash Prozesse beendet. Diese Lösung hat jedoch einen Nachteil: Sobald man auch in der Firmware Prozesse mit bash nutzt, werden diese natürlich auch gekillt. Daher meine Empfehlung: bash nur im chroot und sh und ash in der Firmware :-)

#!/bin/sh

case "$1" in
 'start')
  echo "$(date '+%d.%m.%Y %H:%M:%S') Starting debian chroot"
  mount -t proc none /volume1/debian/proc  > /dev/null 2>&1
  mount -t devpts devpts /volume1/debian/dev/pts > /dev/null 2>&1
  for i in ssh ; do
   chroot /volume1/debian /etc/init.d/$i start
  done
  ;;
  'stop')
   echo "$(date '+%d.%m.%Y %H:%M:%S') Stoping debian chroot"
   for i in ssh ; do
    chroot /volume1/debian /etc/init.d/$i stop
   done
   for i in $(ps | grep '\-bash' | grep -v grep | awk '{print $1}') ; do
    kill -s 9 $i > /dev/null 2>&1
   done

   umount /volume1/debian/proc
   umount /volume1/debian/dev/pts
  ;;
esac

ein Backupvolume einbinden

Hilfreich kann es sein beim Start des chroot ein Verzeichnis der Diskstation für Backups einzubinden. Dazu habe ich bei mir (chroot im RAID1 auf volume1) eine dritte Platte als Basic eingebaut (volume2), welche ich für Backups nutze.

#!/bin/sh

if [ "$*" = 'start' ] ; then
 mkdir -p /volume1/debian/backup
 mount --bind /volume2/.debian_backup /volume1/debian/backup
fi

natürlich den umount beim stop keinesfalls vergessen ;-) Innerhalb des chroot kann man dann nach /backup sichern und die Daten landen effektiv in /volume2/.debian_backup

Geräte aus /dev einbinden

Da das Startscript ja effektiv ausserhalb des chroots läuft kann man mittels mount --bind auch Geräte für den chroot erreichbar machen. Man könnte versucht sein einfach das gesamte /dev der Firmware in den chroot zu mounten. Das ist aber keine gute Idee, ich würde empfehlen das selektiv zu machen

#!/bin/sh

if [ "$*" = 'start' ] ; then
 #die LED der DS für den chroot erreichbar machen
 mount --bind /dev/ttyS1 /volume1/debian/dev/
 #eine externe HD erreichbar machen
 mount /dev/sdk1 /volume1/debian/dev/
fi

zum Thema LED kann man sich mal das folgende angucken hier Wichtig wäre zudem beim mount einer externen Platte via /dev, **__dass das Gerät nicht bereits von der Firmware als volume gemounted wurde__**. Falls das Gerät bereits als volume von der Firmware gemountet wurde kann man sich mit mount --bind abhelfen und einfach ein Verzeichnis auf dieser Platte in den chroot mounten (siehe oben beim Backupverzeichnis mounten)

Stop des chroot verhindern solange ein Backup läuft

Es kann sehr ägerlich sein, wenn man den chroot stoppt solange noch wichtige Prozesse z.B. ein Backup am laufen sind. Das kann man realtiv einfach verhindern. Hier am Beispiel eines Backups durch den Prozess rsnapshot

#!/bin/sh

if [ "$*" = 'stop' ] ; then
 [ -n "$(ps | grep rsnapshot | grep -v grep)" ] && echo "$(date '+%d.%m.%Y %H:%M:%S') Backup running. Delay Shutdown"
  while [ -n "$(ps | grep rsnapshot | grep -v grep)" ]
  do
   echo "$(date '+%d.%m.%Y %H:%M:%S') Checking again in 30s"
   sleep 30
   echo "$(date '+%d.%m.%Y %H:%M:%S') Checking for backup running..."
  done
  echo "$(date '+%d.%m.%Y %H:%M:%S') Backup ended or not running. Resume Shutdown/Reboot"
fi

eigene "Sachen" beenden

Oft hat der geneigte Administrator (aka root) ein paar Scripte am laufen, die in einer Endlosschleife laufen. Solche Script hat man z.B. wenn man ein Script öfter ausführen will als cron mininal zulässt d.h. cron kann minimal jede Minute ein Script ausführen. Wenn man das Script aber alle 25 Sekunden braucht, dann hat man eine Endlosschleife (oft mit sleep) Um solche Prozesse beim Beeenden des chroot auch beendet werden kann man folgendes benutzen

#!/bin/sh

if [ "$*" = 'stop' ] ; then
 for i in script script.sh script1.php script2.pl script3.py sleep  ; do
  for ii in $(ps | grep $i | grep -v grep | awk '{print $1}') ; do
   kill -s 9 $ii
  done
 done
fi

Wichtig

Testet das Start/Stopscript für euren chroot unbedingt bevor ihr einen reboot macht. Die Wahrscheinlichkeit ist gross, dass man am Anfang noch Prozesse des chroots verpasst hat (oder mounts), welche dann den reboot verhindern würden. Ruft das Script manuell mit dem Stop-Parameter auf und prüft danach mittels htop oder top oder ps dass kein einziger Prozess des chroot noch läuft. Eine einzige Shell des chroot kann den reboot verhindern. Auch den Startparameter solltet ihr unbedingt testen, damit ihr seht ob allenfalls noch Fehler im Script sind. Nichts ist blöder als ein ein Fehler beim Startteil des Script, der dann den Start der DS komplett verhindern könnte. Drum testen , testen und nochmals testen :-D