SDB:KIWI Kochbuch Datentrennung

Wechseln zu: Navigation, Suche


Nachbehandlung vom OEM Abbild, verwerfe die Partitionierung.
Getestet mit openSUSE Empfohlene Artikel Verwandte Artikel
Icon-checked.png

Icon-manual.png Icon-help.png


Datentrennung oder Handhabung der Partitionierung

Dieses Beispiel unterstützt einen einfachen Denkansatz zur Trennung der Anwendungsdaten von den Dateien des Betriebssystems.

Immer wenn die Verwendung eines OEM-Abbildes diskutiert wird, in irgend einer Form der Einrichtung, scheint es unvermeidlich, dass irgend jemand nach der Partitionierung fragt. Wie auch immer, woran die meisten Menschen wirklich interessiert sind, ist die Trennung der Anwendungsdaten von den Betriebssystemdaten mit den Mitteln der Partitionierung. Es gibt einen feinen aber wichtigen Unterschied im Spiel, der unten angesprochen wird. Dieses Rezept zeigt, wie man eine Datentrennung für ein OEM-Abbild erreichen kann.


HDD

Datentrennung im Gegensatz zu Partitionen

Vorbereitungszeit:

  • 20 min

Kochzeit:

  • 15 min

Zutaten:

  • ein laufendes openSUSE System
  • ein openSUSE Repository
  • die neueste Ausgabe des KIWI-Werkzeugkastens installiert
  • etwa 1 GB freien Speicherplatz


Partitionierung im Vergleich zur Datentrennung über Aufteilung

Wenn man über Partitionierung spricht, muss man das ganze Spektrum an Möglichkeiten betrachten. Dies schließt beliebig komplizierte Schemen ein, die Partitionen für Verzeichnisse einschließen mögen oder nicht, für die das Betriebssystem sorgt. Dieser Partitionierungstyp während einer normalen interaktiven Installation und während einer Installation mittels AutoYaST unterstützt. In diesem Anwendungsfall könnte ein Benutzer, wenn er möchte, Partitionen erstellen für /opt, /var, /usr, /home, etc. Basisverzeichnisse, die eine spezielle Bedeutung für ein Betriebssystem haben. Dies funktioniert für die interaktive Installation und AutoYaST als ein Prozess, der vor der konkreten Software-Installation auf dem Zielsystem läuft. Wenn die Software-Installation beginnt, werden die Pakete einfach in die geeigneten Zielverzeichnisse entpackt und der Installer selbst schert sich nicht darum, ob das Zielverzeichnis in eine spezielle Partition eingehängt ist oder ob das vorgegebene Verzeichnis einfach Teil der Root-Partition (/) ist.

Für Kiwi funktioniert dieses Schema nicht. Wenn ein Kiwi-Abbild erstellt ist, findet die Installation der Software in einem Verzeichnis statt, unterstützt durch das Argument --root für den Vorbereitungsschritt. In diesem Installationsmodus ist per Definition keine Idee von Partitionen vorhanden. Das Einzige was existiert, ist ein Verzeichnis. Im Erstellungsschritt ist dieses Verzeichnis "einfach" in ein Festplatten-Abbild, für den Abbildtyp "vmx" oder "oem", umgewandelt. Während der OEM-Installation wird das Festplatten-Abbild dann auf das Ziel-Speichermedium verfrachtet. Und so erhalten wir grundsätzlich ein Einzelpartitions-System (außer dem Swap-Bereich). Die Gründe für diese Implementierung können wie folgt erklärt werden:

  1. Es gibt keinen Prozess, der vor der Installation läuft, wenn man ein OEM-System von einem ISO-Abbild oder einem USB-Stick auf der Zielmaschine installiert, ungleich der interaktiven und der Auto YaST-Installation. Sobald das Installations- Medium startet, sind wir im von Kiwi erzeugten Prozess, der das Abbild auf das Ziel-Speicher-Gerät verfrachtet. Darum müsste jedes Partitionierungs-Schema in diesen Selbst-Installations-Prozess integriert werden.
  2. Die Partitionierung kann beliebig kompliziert sein, abhängig von der Speicherplatzkonfiguration auf dem Zielsystem, der Verwendung von primären und erweiterten Partitionen, dem Typ des Dateisystems, der Partitionsgrösse usw. Das führt schnell zum Alptraum des Management-Overhead. Der grundsätzliche Partitionierungscode mit Sondierung, Kalkulation, Fehler-Handhabung usw. ist nicht nur kompliziert einzubringen und zu warten innerhalb der extrem minimalen Selbst-Installations-Umgebung, sondern birgt das mögliche Risiko, dass man schließlich nach der OEM-Verfrachtung bei einem nicht funktionierenden System landen könnte. Das Letztere wäre ein ziemlich unangenehmes Vorkommnis, wenn das bei einem Kunden passieren würde.
  3. Generell wird die Partitionierung im Zusammenhang mit Geräten nicht wirklich benötigt. Wenn Leute von Partitionierung im Zusammenhang mit Geräten sprechen, was grundsätzlich gewünscht ist, ist eine Trennung von Daten für die Anwendungen, die Teil des Gerätes sind, und den Daten (wie /usr, /bin, /sbin, etc.) , die als Teil des Betriebssystems betrachtet werden. Das ist es, worin der feine aber bedeutende Unterschied zwischen der generellen Partitionierung und der Datentrennung über Aufteilung liegt.

Mit diesem im Hinterkopf wird der Rest dieses Beispiels alle notwendigen Informationen liefern, um die Datentrennung über Aufteilung zu erreichen, ohne grundsätzlich Unterstützung einer Partitionierungs-Funktion in Kiwi zu benötigen.

Kiwi unterstützt LVM (Logical Volume Management) als ein Aufteilungsschema in der Datei config.xml für Abbilder die für Festplatten vorgesehen sind vom Typ (vmx und oem). Es ist weiterhin möglich, ein OEM-Abbild so zu erstellen, dass es auf einer vorhandenen Partition installierbar ist, indem man <oem-partition-install> in der Datei config.xml auf true setzt.

Kiwi Abbild Konfiguration

Dieses Beispiel verwendet eine sehr einfache datei config.xml, da der Hauptfokus auf die Erstellung der Datenaufteilung gerichtet ist, die in das Verzeichnis myData eingehängt ist.

Grundeinstellung

Erstellen Sie ein Verzeichnis, um es als Kiwi-Konfigurations-Verzeichnis zu verwenden.

mkdir /tmp/dataSep_exa


Die Datei config.xml

Verwenden Sie Ihren bevorzugten Editor und erstellen Sie /tmp/dataSep_exa/config.xml. Sie können das Beispiel unten kopieren und einfügen, Ihren eigenen Inhalt von Grund auf erstellen oder das Beispiel modifizieren, um die Pakete einzubinden, die Sie gerne enthalten haben möchten.

<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="4.7" name="suse-11.3-oem-dataseparation">
    <description type="system">
        <author>Robert Schweikert</author>
        <contact>rschweikert at novell dot com</contact>
        <specification>
            openSUSE 11.3 based example showing data separation based on 
            partitions
        </specification>
    </description>
    <preferences>
        <type image="oem" filesystem="ext4" boot="oemboot/suse-11.3" installiso="true">
            <oemconfig>
                <oem-boot-title>Data-Separation</oem-boot-title>
                <oem-home>false</oem-home>
                <oem-swap>true</oem-swap>
                <oem-swapsize>4096</oem-swapsize>
                <oem-systemsize>8192</oem-systemsize>
            </oemconfig>
        </type>
        <version>1.0.0</version>
        <packagemanager>zypper</packagemanager>
        <keytable>us.map.gz</keytable>
        <timezone>US/Eastern</timezone>
        <rpm-excludedocs>true</rpm-excludedocs>
    </preferences>
    <users group="root">
        <user pwd="linux" pwdformat="plain" home="/root" name="root"/>
    </users>
    <users group="users">
        <user pwd="linux" pwdformat="plain" home="/home/tux" name="tux"/>
    </users>
    <repository type="yast2">
       <source path="opensuse://11.3/repo/oss/"/>
    </repository>
    <packages type="image" patternType="plusRecommended">
        <package name="kernel-default"/>
        <package name="ifplugd"/>
        <package name="python"/>
        <package name="vim"/>
        <namedCollection name="default"/>
    </packages>
    <packages type="bootstrap">
        <package name="filesystem"/>
        <package name="glibc-locale"/>
    </packages>
</image>

Es gibt wirklich nichts spezielles über die vorherige Konfigurationsdatei. Beachten Sie, dass das Elemente <oem-systemsize> verwendet wird, um die Größe des OS-Abbildes zu begrenzen, in diesem Fall auf 8 GB. Innerhalb 8 GB kann man eine ganze Menge installieren, alle Pakete die mit einer Standard SUSE-Distribution veröffentlicht werden. Die Pakete und Muster (Pattern), die in der obigen Datei config.xml ausgewählt wurden, geben eine minimale Auswahl wieder, da mit dem Beispiel beabsichtigt ist, das Konzept zu demonstrieren und nicht die Erstellung einer brauchbaren Anwendung. Python wird verwendet, um das Script auszuführen, das verwendet wird, um die Datentrennung zu erzeugen.

Das Element <oem-systemsize> begrenzt den Speicherplatz, der von der Root-Partition verwendet wird. Das lässt einigen extra Platz auf dem Speichermedium unangetastet. Ohne die Verwendung des Elements <oem-systemsize> würde sich das Root-System-Abbild auf den verfügbaren Speicherplatz auf dem Medium ausdehnen. Das lässt keinen Platz für extra Aufteilungs-Operationen. Darum ist die Verwendung des Elements <oem-systemsize> erforderlich, wenn Sie zusätzliche Partitionen erstellen müssen, nachdem das System auf das Ziel-Speichergerät verfrachtet wurde.

Wenn Sie Ihre eigene Anwendung in den Bau einbinden, könnten Sie eine geeignete Menge Speicherplatz hinzufügen wollen, um die Binärdateien für Ihre Anwendung anzupassen. Fügen Sie keinen Speicherplatz für Ihre Anwendungsdaten hinzu, da wir die Daten auf eine getrennte Partition geben werden, was schließlich das Anliegen von diesem Beispiel ist.

Die Datei config.sh

Das Script config.sh für die Konfiguration wurde nicht dargestellt, da es ein "Standard" config.sh-Script ist, das Info-Dateien löscht, usw. wie im vorherigen Rezept.

Partition Einrichtung

Zuerst erstellen Sie einen Ort für das Script in unseren Kiwi-Konfigurations-Baum.

mkdir -p /tmp/dataSep_exa/root/sbin


Dann erstellen Sie mit Ihrem bevorzugten Editor die Datei /tmp/dataSep_exa/root/sbin/setUpPartitions. Kopien Sie das Script-Beispiel unten, um dem Beispiel zu folgen oder das Script nach Ihren Vorstellungen zu verändern.

#!/usr/bin/python

import os
import time

def getSizeAndUnit(valueStr):
    """Extrahiere die Information zu Zahl und Einheit aus einer Zeichenkette des Formats 111MB"""

    size = ''
    idx = 0
    for char in valueStr:
        if char.isdigit() or char == '.':
            size += char
            idx += 1

    unit = valueStr[idx:]

    return size, unit

diskInfoCmd = '/usr/sbin/parted %s print' %(os.environ["imageDiskDevice"])
diskInfo = os.popen(diskInfoCmd).readlines()
partCnt = 0

diskSize = ''
diskUnit = ''
lastPartEnd = ''
lastPartEndUnit = ''

foundPartTbl = None
numPartitions = 0
for diskLn in diskInfo:
    if diskLn.find('Disk') != -1:
        diskSize, diskUnit = getSizeAndUnit(diskLn.split(':')[-1].strip())
        continue
    
    if diskLn.find('Number') != -1:
        foundPartTbl = 1
        continue
    
    if foundPartTbl and diskLn.split():
       numPartitions += 1
       lastPartEnd, lastPartEndUnit = getSizeAndUnit(diskLn.split()[2])

if (lastPartEnd == diskSize) and (lastPartEndUnit == diskUnit):
    print "No free space on device"
    exit(1)

# Erstelle die Partition, die den kompletten verfügbaren Speicherplatz verwendet
partCmd = '/usr/sbin/parted %s mkpart primary %s%s %s%s >& /dev/null' %(
                                                os.environ["imageDiskDevice"],
                                                lastPartEnd,
                                                lastPartEndUnit,
                                                diskSize,
                                                diskUnit)
os.system(partCmd)

# Erzwinge, dass die Partitionstabelle erneut gelesen wird
partReadCmd = 'partx -a %s >& /dev/null' %(os.environ["imageDiskDevice"])
os.system(partReadCmd)

# Erstelle das Dateisystem auf der neuen Partition
fsCmd = '/sbin/mkfs -t ext4 %s%d >& /dev/null' %(os.environ["imageDiskDevice"],
                                                 numPartitions + 1)
os.system(fsCmd)

# Bestimme die Platten ID auf dem vorhandenen fstab Eintrag
fstabData = open('/etc/fstab', 'r').readlines()
diskID = ''
for fstabLn in fstabData:
    if fstabLn.find('by-id') != -1:
        diskID = fstabLn.split()[0]
        break

# Erzeuge einen Eintrag in /etc/fstab    
fstab = open('/etc/fstab', 'a')
fstab.write('\n\n#Autogenerated data partition information\n')
fstab.write(diskID[:diskID.index('part')])
fstab.write('part%d' %(numPartitions + 1))
fstab.write('  /myData')
fstab.write('  ext4')
fstab.write('  defaults 1 2\n')
fstab.close()

# Gib dem System etwas Zeit, die Änderungen einzurichten
time.sleep(10)

# Erstelle einen Einhängepunkt und hänge die neue Partition ein
os.mkdir('/myData')
mntCmd = '/bin/mount /myData >& /dev/null'
os.system(mntCmd)

# Bereinigung
os.system('rm /tmp/partSetup')
bootInfo = open('/etc/init.d/boot.local', 'r').readlines()
bootLocal = open('/etc/init.d/boot.local', 'w')

skipBlock = None
for ln in bootInfo:
    if ln.find('# Begin init data setup') != -1:
        skipBlock = 1
    if ln.find('# End init data setup') != -1:
        skipBlock = None
        continue
    if skipBlock:
        continue
    bootLocal.write(ln)

bootLocal.close()

os.system('rm sbin/setUpPartitions')

Sichere die Datei und füge die Ausführungserlaubnis hinzu.

chmod +x /tmp/dataSep_exa/root/sbin/setUpPartitions


Lassen Sie uns das Script näher betrachten. Zuerst ist eine Funktion definiert, die eine Zeichenkette der Form "12.6GB" in zwei Zeichenketten teilt. Die erste Zeichenkette die erwidert ist die Größe, "12.6" in diesem Fall, und die zweite ist die Einheit "GB" in diesem Beispiel.

Der Funktionsdefinition folgend sammeln wir die Information, die von parted /dev/sda print geliefert wird, so dass wir die Daten zerlegen können und extrahieren können, was für uns nützlich ist.

In diesem Rezept wird angenommen, dass das Abbild auf dem ersten Speichergerät, das erkannte wird, installiert wird (/dev/sda) und dass die Datenpartition auch auf diesem Gerät platziert wird.

Die for-Schleife überprüft einfach die Ausgabe vom Kommando parted und extrahiert die interessierenden Daten. Die Größe des Speichergeräts ist in der Variablen diskSize enthalten, die aus einer Zeile in der geteilten Ausgabe extrahiert wurde, die mit Disk anfängt. Die berichtete Einheit für die Speichergröße in der Variablen diskUnit gespeichert. Die Schleife zählt auch die vorher existierenden Partitionen (numPartitions counter) und legt die Größe mit der die letzte vorhandene Partition endet unter der Variablen lastPartEnd ab. Die Einheit des Endes der letzten Partition wird unter der Variablen lastPartEndUnit abgelegt.

In diesem Rezept gibt es zwei bereits existierende Partitionen, die Root-Partition (/) und die Swap-Partition.

Ein schneller Vergleich des Endes der letzten Partition und die Größe der Festplatte bestimmt, ob noch Speicherplatz zur Verfügung steht.

Nachdem wir wissen, dass noch Speicherplatz vorhanden ist, erzeugt das Script einfach eine einzelne Partition, die am Ende der vorherigen letzten Partition beginnt und den ganzen noch verfügbaren Speicherplatz einnimmt. Man kann einen willkürlichen Algorithmus hier einfügen, um ein Partitions-Layout nach eigenen Wünschen zu erzeugen. Behalten Sie im Hinterkopf, dass jedes vorhandene Speichergerät nur 4 primäre Partitionen haben kann.

Nach Partitions-Erzeugung, wird ein Dateisystem auf der Partition erstellt, ext4 in diesem Beispiel.

Als nächstes erzwingt das Script den laufenden Kernel die Partitions-Tabelle neu zu lesen, das Kommando partx, um sicher zu stellen, dass die geeigneten Geräteknoten in /dev erstellt sind.

Nachdem die neuen Geräteknoten erstellt sind, hängt das Script eine neue Zeile in der Datei /etc/fstab an, um sicher zu stellen, dass unsere Partition zur Boot-Zeit eingehängt ist. Nach einem kurzen Schlaf, um dem System Zeit zu geben, auf den neuesten Stand zu kommen, wird das Einhängepunktverzeichnis erstellt und die neue Partition eingehängt.

Zum Schluss räumt das Script die Datei boot.local auf (das wird unten gezeigt und diskutiert) und dann löscht sie sich selbst vom System. Es wird keine Spur dieser Partitions-Zauberei, die gerade passierte, hinterlassen.

Anstoßen des Partitionierungs-Prozesses

Wir wollen die Partitionierung so einrichten, dass sie aus der Gerätebenutzerperspektive unsichtbar ist. Da alles was wir brauchen, auf einem laufenden System ausgeführt werden kann, können wir das Partitionierungsscript während des Boot-Prozesses starten. Und wir brauchen uns keine Gedanken über die Verwendung des Yast Firstboot Mechanismus zu machen.

Erstellen Sie das Verzeichnis init.d in Ihrem Kiwi-Konfigurations-Baum.

mkdir -p /tmp/dataSep_exa/root/etc/init.d


Mit Ihrem bevorzugten Editor erstellen Sie /tmp/dataSep_exa/root/etc/init.d/boot.local und folgen dem Beispiel, kopieren das untere Script und fügen es ein.

#! /bin/sh

# Beginn des init Daten setup
if [ -f /tmp/partSetup ]; then
    /sbin/setUpPartitions
fi
# Ende des init Daten setup

Sie können die Kommentare sehen, die von Partitionierungs-Script verwendet werden, um für die Existenz der Trigger-Datei in /tmp aufzuräumen und zu testen.

Für ein mehr modulares Design sollte das Partitionierungs-Script nicht boot.local aufräumen. Diese Aufgabe sollte von einem getrennten Script ausgeführt werden. Für dieses Beispiel wird das Mischen von Verantwortlichkeiten ausreichen. In einer Produktionsumgebung sollte man die Angelegenheiten eindeutig trennen. Vergessen Sie nicht das Script boot.local ausführbar zu machen und erstellen Sie eine Trigger-Datei im Kiwi-Konfigurationsbaum.


chmod +x /tmp/dataSep_exa/root/etc/init.d/boot.local
mkdir /tmp/dataSep_exa/root/tmp
touch /tmp/dataSep_exa/root/tmp/partSetup


Das vervollständigt die Einrichtung des Konfigurationsbaums.

Bau und Test des Beispiels

Es gibt nichts spezielles zum Bau, wenn die vorhergehenden Rezepte vergleicht.

kiwi --prepare /tmp/dataSep_exa --root /tmp/dataSep_unpacked
kiwi --create /tmp/dataSep_unpacked -d /tmp/dataSep_image


Nun erstellen Sie ein Festplatten-Abbild mit einer willkürlichen Größe (250 GB in diesem Beispiel).

qemu-img create -f qcow2 /tmp/dataSep.img 250G


Mit dem Festplatten-Abbild können wir nun Qemu verwenden, um das OEM-Abbild zu testen, das wir mit Kiwi erstellt haben.

qemu-kvm /tmp/dataSep.img -cdrom /tmp/dataSep_image/suse-11.4-oem-dataseparation.x86_64-1.0.0.iso -boot d


Ihr ISO-Datei-Name wird anders sein, wenn Sie auf einer 32 bit Plattform bauen. Ebenso sei an die vorher erwähnten Vorbehalte bezüglich von 64 bit Anwendungen erinnert.

Wenn das Abbild startet, werden Sie den Selbstinstallationsprozess wie gewöhnlich sehen, gefolgt vom Boot-Prozess des installierten Systems. Wenn Sie auf dem Anmeldebildschirm sind, melden Sie sich als Root an, Passwort linux und listen die Partitionstabelle mit dem folgenden Kommando auf:

parted -l


Sie werden sehen, dass da nun 3 Partitionen auf dem System sind. Wenn Sie das Kommando mount eingeben, werden Sie sehen, dass /dev/sda3 unter /myData eingehängt ist.