Website-Suche

So schreiben und führen Sie unbeaufsichtigte Ubuntu-Installationen mit autoinstall durch


Die Möglichkeit, replizierbare Installationen eines Betriebssystems bereitzustellen und zu erstellen, ist insbesondere in Unternehmensumgebungen von entscheidender Bedeutung. Um unbeaufsichtigte Installationen durchzuführen, unterstützte Ubuntu Debian-Preseed- und Kickstart-Dateien. Beginnend mit Ubuntu Server 20.04 und Version 23.04 des Ubuntu-Desktops wurden diese Installationsmethoden veraltet, und die Distribution übernahm ein neues Autoinstall-Format, das die Vorteile von cloud-init nutzt.

In diesem Tutorial lernen wir, wie man eine Ubuntu-Autoinstall-Datei schreibt und wie man sie verwendet, um unbeaufsichtigte, replizierbare Installationen durchzuführen.

In diesem Tutorial lernen Sie:

  • Wie man eine Autoinstall-Datei schreibt und eine Ubuntu-Installation in all ihren Aspekten definiert
  • So übergeben Sie die Autoinstall-Datei an die Ubuntu-Desktop- und -Server-Installationsprogramme

Einführung in die Autoinstall-Datei

Da es sich um eine von Debian abgeleitete Distribution handelt, unterstützte Ubuntu ursprünglich Preseed-Dateien als Methode zur Durchführung unbeaufsichtigter und replizierbarer Installationen. Die Unterstützung der Kickstart-Installationssyntax wurde später als Kompatibilitätsebene hinzugefügt, aber nicht alle Kickstart-Befehle wurden implementiert. Beginnend mit dem Ubuntu-Server 20.04 und seit dem Ubuntu-Desktop 23.04 hat Ubuntu eine eigene Methode zur automatischen Installation eingeführt, die auf der YAML-Syntax basiert: autoinstall.

Das erste, was wir normalerweise in Autoinstall-Dateien sehen, ist der Kommentar "#cloud-config": Dieser ist erforderlich, wenn wir möchten, dass die Datei von cloud-init verarbeitet wird (dazu später mehr). Der Hauptschlüssel, der in der Konfigurationsdatei verwendet wird, ist autoinstall. Stattdessen wird die Version der Dateisyntax mit dem Versionsschlüssel angegeben. Zum Zeitpunkt des Schreibens ist nur Version 1 verfügbar:

#cloud-config
autoinstall:
  version: 1

Auswahl einer Quelle

Um die "Umgebung" anzugeben, die wir installieren möchten, können wir den Quellschlüssel verwenden, der ein Mapping als Wert annimmt. In dieser Zuordnung übergeben wir den Namen der Umgebung, die wir installieren möchten, als Wert des ID-Schlüssels. Bei der Installation des Ubuntu-Desktops können wir beispielsweise zwischen ubuntu-minimal-desktop und dem vollwertigen ubuntu-desktop wählen. Wenn der Schlüssel weggelassen wird, wird die erste verfügbare Quelle verwendet:

#cloud-config
autoinstall:
  source:
    id: ubuntu-desktop-minimal

Festlegen des Systemgebietsschemas, der Zeitzone und des Tastaturlayouts

Um das Gebietsschema des Systems festzulegen, verwenden wir den Schlüssel locale. Tastatureinstellungen werden stattdessen über die Tastaturtaste festgelegt. Dieser Schlüssel nimmt eine Zuordnung als Wert an. Im folgenden Beispiel geben wir nur das Layout an, das wir verwenden möchten (uns); Es ist auch möglich, andere Parameter anzugeben, wie z.B. die Layout-Variante. Um schließlich die Systemzeitzone festzulegen, verwenden wir den Zeitzonenschlüssel:

#cloud-config
autoinstall:
  locale: en_US.UTF-8
  keyboard:
    layout: us
  timezone: Europe/Rome

Konfigurieren von Netzwerkschnittstellen

Um das Systemnetzwerk zu konfigurieren, verwenden wir den Netzwerkschlüssel mit der netplan-Syntax. Im folgenden Beispiel gebe ich an, dass die enp1s0-Ethernet-Schnittstelle automatisch über dhcp4 konfiguriert werden soll:

#cloud-config
autoinstall:
  network:
    version: 2
    ethernets:
      enp1s0:
        dhcp4: true

Konfigurieren des Hostnamens und des anfänglichen Systembenutzers

Um unser System sicher nutzen zu können, müssen wir mindestens einen unprivilegierten Benutzer erstellen. Wir müssen auch den Hostnamen des Systems festlegen. Beide Aspekte werden über den Identitätsschlüssel verwaltet. Der Schlüssel nimmt eine Zuordnung als Wert an; Wir definieren den Benutzernamen, das Passwort und den Hostnamen mit den entsprechenden Schlüsseln:

#cloud-config
autoinstall:
  identity:
    username: egidio
    hostname: linuxconfig
    password: '$6$mzOdSSVUfhWRNhcX$mkm.drDfOLfpZRX/58ouJqMvitV2O0147VgKzKGYE6Qx4adJ8TXqMHs2dh2L7kT4TW5e97FCRDkGK1J.LouyV.'

Wie Sie im Beispiel sehen können, muss das von uns bereitgestellte Passwort bereits mit dem sha512-Algorithmus gehasht worden sein.

Einrichten des SSH-Servers

In der Autoinstall-Datei haben wir die Möglichkeit anzugeben, ob wir den SSH-Server installieren und konfigurieren möchten. Wir können die Passwortauthentifizierung aktivieren oder deaktivieren und schließlich die Liste der autorisierten öffentlichen Schlüssel übergeben, die der authorized_keys Datei des ersten Benutzers hinzugefügt werden:

#cloud-config
autoinstall:
  ssh:
    install-server: true
    allow-pw: true
    authorized-keys: []

Installieren zusätzlicher Pakete

Um eine Liste von zusätzlichen Paketen zu spezifizieren, die vom apt-get-Paketmanager als Teil der Systeminstallation abgerufen werden sollen, können wir den Schlüssel packages verwenden. Hier ist ein Beispiel:

#cloud-config
autoinstall:
  packages:
    - git
    - python3-pip

Um Snap-Pakete zu installieren, verwenden wir stattdessen das Schlüsselwort snaps. Das Schlüsselwort akzeptiert eine Liste von Zuordnungen als Wert. In jedem Mapping verwenden wir den Schlüssel, den Kanal und den klassischen Schlüssel, um den Namen des zu installierenden Snap-Pakets, den Kanal, von dem aus der Snap installiert werden soll (der Standardwert ist "stable") und ob das Snap-Paket im klassischen Modus installiert werden soll (der Standardwert ist "false"):

#cloud-config
autoinstall:
  snaps:
    - name: pycharm-community
      channel: stable 
      classic: true

Definieren der Aktion nach der Installaktion

Um die Aktion nach der Installation zu definieren, verwenden wir den Schlüssel shutdown. Dieser Schlüssel akzeptiert zwei mögliche Werte: "poweroff" und "reboot":

#cloud-config
autoinstall:
  shutdown: reboot

Definieren der Speichereinrichtung

Einer der wichtigsten Aspekte der Systeminstallation ist die Einrichtung der Partitionierung. Bei der interaktiven Installation von Ubuntu können wir zwischen einigen vordefinierten Layouts wählen oder ein benutzerdefiniertes Setup erstellen. Das Gleiche können wir bei automatischen Installationen tun. Die verfügbaren vordefinierten Layouts sind: lvm, direct und zfs.

Das LVM-Layout ist die Standardeinstellung: Es erstellt die EFI- (im Falle moderner UEFI-Systeme) und Boot-Standardpartitionen und installiert den Rest des Systems auf einem logischen LVM-Volume. Die Größe des logischen Root-Volumes wird gemäß einer Richtlinie bestimmt: Wenn es auf "skaliert" (Standard) festgelegt ist, hängt die Menge an Speicherplatz, die dem logischen Volume zugewiesen ist, von der Größe der Volume-Gruppe ab. Wenn möglich, wird etwas Platz ungenutzt gelassen, um die Erstellung von Snapshots zu ermöglichen:

VG GrößeGröße der Wurzel-LV
Weniger als 10 GiB100% des verfügbaren Platzes
Zwischen 10 GiB und 20 GiB10 GiB
Zwischen 20 GiB und 200 GiB50% des verfügbaren Platzes
Mehr als 200 GiB100 GiB

Wenn die Richtlinie auf "all" festgelegt ist, wird stattdessen der gesamte verfügbare Speicherplatz dem logischen Root-Volume zugewiesen. In diesem Zusammenhang kann derPasswortschlüssel verwendet werden, um die LUKS-Verschlüsselung zu aktivieren und das Verschlüsselungspasswort bereitzustellen:

#cloud-config
autoinstall:
  storage:
    layout:
      name: lvm
      policy: all
      password: mysecretpassword

Das direkte Layout installiert Ubuntu auf Standardpartitionen. Auf UEFI-Systemen wird eine EFI-Partition mit einer Größe von 1 GiB erstellt und der Rest des Speicherplatzes der Stammpartition zugewiesen.

Schließlich installiert das zfs-Layout das System in einem ZFS-Pool, wodurch mehrere Volumes erstellt werden. Unten sehen Sie einen Screenshot des zfs-Setups nach einer Neuinstallation von Ubuntu:

Auswählen eines Datenträgers für die Installation

Zusätzlich zu den Partitionslayouts können wir explizit festlegen, welche Festplatte für die Installation verwendet werden soll. Wir tun dies über den Match-Key. Wir können eine Festplatte nach Pfad, Hersteller, Modell, Seriennummer und mehr auswählen. Wenn das Schlüsselwort weggelassen wird, erfolgt die Installation auf dem größten verfügbaren Datenträger. Im folgenden Beispiel wählen wir eine Festplatte über den Pfad (/dev/vda) aus:

#cloud-config
autoinstall:
  storage:
    layout:
      name: lvm
      match:
        path: /dev/vda

Erstellen eines benutzerdefinierten Layouts

Um ein benutzerdefiniertes Partitionslayout zu definieren, verwenden wir das Schlüsselwort config. Dieses Schlüsselwort akzeptiert eine Liste von Zuordnungen als Wert, die jeweils einen Befehl des Curtin-Installers beschreiben. Sehen wir uns ein Beispiel an. Angenommen, wir möchten Ubuntu auf einem LVM auf LUKS-Setup installieren und die folgenden Partitionen erstellen:

  1. Eine kleine EFI-Partition von 600 MiB, formatiert in fat32, die auf /boot/efi gemountet werden soll
  2. Eine Boot-Partition von 1 GiB, formatiert in ext4, um auf /boot gemountet zu werden
  3. Eine dritte Partition, die sich über den Rest des Speicherplatzes erstreckt, mit LUKS verschlüsselt und als physisches LVM-Volume formatiert ist
  4. Ein logisches LVM-Volume mit 45 GiB, das auf /
  5. Ein logisches LVM-Volume mit 50 GiB, das auf /home gemountet werden kann

So gehen wir vor. Das erste, was wir tun müssen, ist den Befehl disk zu verwenden. Es wird verwendet, um Festplatten einzurichten und Partitionstabellen zu erstellen:

#cloud-config
autoinstall:
  storage:
    config:
      - id: disk-vda
        type: disk
        ptable: gpt
        path: /dev/vda
        wipe: superblock-recursive

Mit dem Schlüsselwort id geben wir eine Kennung für die Sektion und den Befehl an: Dies ermöglicht es uns, die Festplatte zu referenzieren, wenn wir andere Befehle verwenden. Mit dem Schlüsselwort type geben wir stattdessen den Befehl an, den wir ausführen möchten, in diesem Fall "disk".

Wenn der Schlüssel ptable vorhanden ist, wird eine Partitionstabelle des angegebenen Typs auf der Festplatte erstellt. In diesem Fall haben wir "gpt" als Wert verwendet. Das Schlüsselwort path wird verwendet, um den Datenträger anhand seines Pfads (/dev/vda) zu identifizieren.

Das Schlüsselwort wipe ist sehr wichtig: Wenn es verwendet wird, zerstört es den Inhalt von Festplatten oder Partitionen. Es gibt viele Arten von "Wipe", die wir verwenden können: Superblock, Superblock-rekursiv, Null, Zufall und pvremove. Wir verwenden superblock, wenn wir nur den Superblock der Festplatte löschen möchten, und superblock-rekursiv, wenn wir auch eventuelle Einbettungs-Superblöcke löschen möchten (sie können z.B. bei der Verwendung von LVM vorhanden sein). Mit den Zero- oder Rando-m-Wipes können wir die Festplatte mit Nullen bzw. zufälligen Daten überschreiben. Schließlich löscht pvremove speziell LVM-Metadaten, um sicherzustellen, dass die Festplatte nicht Teil eines LVM-Setups ist. Im obigen Beispiel haben wir superblock-recursive verwendet, was in den meisten Fällen ausreichen sollte.

Erstellen von Standardpartitionen mit dem Befehl "partition"

Wir müssen nun die drei "Standard"-Partitionen auf der Festplatte erstellen. Die erste ist die EFI-Partition, die zweite die Partition, die auf /boot gemountet wird, und die dritte ist die Partition, die mit LUKS verschlüsselt und als physisches LVM-Volume verwendet wird. Um eine Partition zu erstellen, verwenden wir den Befehl partition. In den folgenden Beispielen konzentrieren wir uns der Übersichtlichkeit halber auf die aktuellen Befehle und lassen die zuvor verwendeten aus:

#cloud-config
autoinstall:
  storage:
    config:
      # [...]

      - id: efipart
        type: partition
        device: disk-vda
        offset: 1048576
        size: 600M
        flag: boot
        grub_device: true

      - id: bootpart
        type: partition
        device: disk-vda
        size: 1G

      - id: pvpart
        type: partition
        device: disk-vda
        size: -1

Da die "efipart"-Partition die erste ist, haben wir das Schlüsselwort offset verwendet, um sicherzustellen, dass sie mit 1 MiB vom Anfang der Festplatte an erstellt wird (der Wert wird in Bytes angegeben: 1048576). Wir haben das Schlüsselwort flag verwendet, um ein Flag anzugeben, das auf der Partition gesetzt werden soll, in diesem Fall "boot". Schließlich haben wir das Schlüsselwort grub_device verwendet, um sicherzustellen, dass GRUB auf der Partition installiert ist.

In allen Definitionen haben wir den Geräteschlüssel verwendet, um auf die Festplatte zu verweisen, auf der die Partition erstellt werden muss, und den Größenschlüssel, um die Partitionsgröße anzugeben. Im Fall der "pvpart"-Partition verwenden wir "-1" als Wert: Dies stellt sicher, dass die Partition den gesamten verbleibenden Speicherplatz auf der Festplatte belegt.

Erstellen eines verschlüsselten LUKS-Volumes mit dem Befehl dm_crypt

Als nächsten Schritt wollen wir LUKS verwenden, um die "pvpart"-Partition zu verschlüsseln. Wir können dies mit dem Befehl dm_crypt tun:

#cloud-config
autoinstall:
  storage:
    config:
      # [...]

      - id: pvpart-crypt
        type: dm_crypt
        volume: pvpart
        key: mysecretpassword

Wenn wir den Befehl dm_crypt verwenden, übergeben wir die Kennung der Partition, die wir verschlüsseln möchten, als Wert des Volume-Schlüssels, und wir verwenden den Schlüssel, um die Verschlüsselungspassphrase bereitzustellen.

Erstellen der LVM-Datenträgergruppe und der logischen Datenträger

Um eine LVM-Volume-Gruppe zu erstellen, verwenden wir den Befehl lvm_volgroup und verwenden das Schlüsselwort devices, um die physischen Volumes aufzulisten, die wir der Gruppe hinzufügen möchten:

#cloud-config
autoinstall:
  storage:
    config:
      # [...]
     
      - id: vg0
        type: lvm_volgroup
        name: vg0
        devices:
          - pvpart-crypt

Um logische Volumes zu erstellen, verwenden wir den Befehl lvm_partition. Wir geben den LV-Namen mit dem Namensschlüssel, die Volume-Gruppe, auf der der LV als Wert von volgroup erstellt werden soll, und seine Größe über den Größenschlüssel an:

#cloud-config
autoinstall:
  storage:
    config:
      # [...]
      - id: root_lv
        type: lvm_partition
        name: root_lv
        volgroup: vg0
        size: 45G
 
      - id: home_lv
        type: lvm_partition
        name: home_lv
        volgroup: vg0
        size: 50G

Formatieren der Partitionen

Um Dateisysteme auf den von uns definierten Partitionen zu erstellen und ihre Einhängepunkte zu setzen, verwenden wir den Befehl format. Wir verwenden das Schlüsselwort volume, um die Partition anhand der ID zu referenzieren, und das Schlüsselwort fstype, um anzugeben, welches Dateisystem erstellt werden soll:

#cloud-config
autoinstall:
  storage:
    config:
      # [...]
    
      - id: efipart_fs
        type: format
        volume: efipart
        fstype: fat32

      - id: bootpart_fs
        type: format
        volume: bootpart
        fstype: ext4

      - id: root_lv_fs
        type: format
        volume: root_lv
        fstype: ext4

      - id: home_lv_fs
        type: format
        volume: home_lv
        fstype: ext4

Um schließlich anzugeben, wo das Dateisystem eingehängt werden soll, verwenden wir den Befehl mount. Mit dem Geräteschlüssel geben wir die Dateisystem-ID an; mit path stattdessen seinen Mountpoint:

#cloud-config
autoinstall:
  storage:
    config:
      # [...]
     
      - id: efipart-mount
        type: mount
        device: efipart_fs
        path: /boot/efi

      - id: bootpart-mount
        type: mount
        device: bootpart_fs
        path: /boot

      - id: root_lv_mount
        type: mount
        device: root_lv_fs
        path: /

      - id: home_lv_mount
        type: mount
        device: home_lv_fs
        path: /home

Übergeben der Konfiguration an das Ubuntu-Installationsprogramm

So sieht unsere Konfigurationsdatei für die automatische Installation in ihrer Gesamtheit aus:

#cloud-config
autoinstall:
  version: 1

  source:
    id: ubuntu-server-minimal

  locale: en_US.UTF-8
  keyboard:
    layout: us
  timezone: Europe/Rome

  network:
    version: 2
    ethernets:
      enp1s0:
        dhcp4: true

  identity:
    username: egidio
    hostname: linuxconfig
    password: '$6$mzOdSSVUfhWRNhcX$mkm.drDfOLfpZRX/58ouJqMvitV2O0147VgKzKGYE6Qx4adJ8TXqMHs2dh2L7kT4TW5e97FCRDkGK1J.LouyV.'

  ssh:
    install-server: true
    allow-pw: true
    authorized-keys: []

  packages:
    - git
    - python3-pip

  snaps:
    - name: pycharm-community
      channel: stable 
      classic: true

  shutdown: reboot
  storage:
    config:
      - id: disk-vda
        type: disk
        ptable: gpt
        path: /dev/vda
        wipe: superblock-recursive

      - id: efipart
        type: partition
        device: disk-vda
        offset: 1048576
        size: 600M
        flag: boot
        grub_device: true

      - id: bootpart
        type: partition
        device: disk-vda
        size: 1G

      - id: pvpart
        type: partition
        device: disk-vda
        size: -1

      - id: pvpart-crypt
        type: dm_crypt
        volume: pvpart
        key: mysecretpassword

      - id: vg0
        type: lvm_volgroup
        name: vg0
        devices:
          - pvpart-crypt

      - id: root_lv
        type: lvm_partition
        name: root_lv
        volgroup: vg0
        size: 45G
 
      - id: home_lv
        type: lvm_partition
        name: home_lv
        volgroup: vg0
        size: 50G

      - id: efipart_fs
        type: format
        volume: efipart
        fstype: fat32

      - id: bootpart_fs
        type: format
        volume: bootpart
        fstype: ext4

      - id: root_lv_fs
        type: format
        volume: root_lv
        fstype: ext4

      - id: home_lv_fs
        type: format
        volume: home_lv
        fstype: ext4

      - id: efipart-mount
        type: mount
        device: efipart_fs
        path: /boot/efi

      - id: bootpart-mount
        type: mount
        device: bootpart_fs
        path: /boot

      - id: root_lv_mount
        type: mount
        device: root_lv_fs
        path: /

      - id: home_lv_mount
        type: mount
        device: home_lv_fs
        path: /home

Wie übergebe ich die Konfiguration an das Ubuntu-Installationsprogramm? Bei der Installation der Desktop-Version von Ubuntu besteht die einfachste und bequemste Methode darin, unsere Konfigurationsdatei über HTTP oder FTP zur Verfügung zu stellen und ihre URL im entsprechenden Abschnitt des grafischen Installationsprogramms zu übergeben:

Eine Autoinstall-Konfigurationsdatei wird automatisch nach jeder Ubuntu-Installation erstellt, auch nach solchen, die interaktiv durchgeführt werden. Sie finden die Datei als /var/log/installer/autoinstall-user-data gespeichert. Die Datei kann verwendet werden, um die Installation zu replizieren.

Wenn wir eine vollständig automatisierte Installation durchführen oder die Autoinstall-Konfiguration bei der Installation des Ubuntu-Servers verwenden möchten, müssen wir cloud-init verwenden und die Konfiguration als cloud-config-Datendatei verwenden: Dafür ist der Kommentar "#cloud-config" ganz am Anfang der Autoinstall-Datei gedacht.

Damit cloud-init die Datei beim Booten lesen kann, müssen wir sie in user-data umbenennen und eine leere Datei mit dem Namen meta-data im selben Verzeichnis erstellen. Wir drücken "e", um den ersten Eintrag des Live-ISO-GRUB-Menüs zu ändern:

Dann ändern wir die Zeile, die mit "linux" beginnt, und fügen den folgenden String vor die drei Bindestriche ein (das Semikolon zu vermeiden ist wichtig!):

autoinstall ds=nocloud-net\;s=<directory-URL>

Dabei ist <Verzeichnis-URL> die URL des Verzeichnisses, das die Benutzerdaten- und Metadatendateien enthält:

Um die Installation zu starten, drücken wir an dieser Stelle einfach Strg-x.

Abschließende Gedanken

Seit Ubuntu Server 20.04 und Ubuntu Desktop 23.04 ist es möglich, unbeaufsichtigte und reproduzierbare Systeminstallationen im nativen Autoinstall-Format durchzuführen. In diesem Tutorial haben wir gesehen, wie man eine Autoinstall-Datei schreibt, und einige der Schlüssel, die darin verwendet werden können. Schließlich haben wir gesehen, wie die Datei an die Ubuntu-Desktop- und Server-Installationsprogramme übergeben wird. Eine vollständige Referenz zur Ubuntu-Autoinstallation finden Sie in der offiziellen Dokumentation.

Verwandte Artikel: