[aarch64] systemd-nspawn Container für ODROID-C2

Für eine Containervirtualisierung mittels systemd-nspawn auf einem ODROID-C2, stelle ich hier eine kleine Anleitung bereit, wie man ein Wurzeldateisystem auf Basis von Arch Linux erstellt.

Zunächst laden wir das mkimage-arch.sh Skript herunter, um das Wurzeldateisystem zu erstellen. Das Skript ist ursprünglich dafür gedacht ein Arch Linux Image für Docker zu erstellen; in dieser Anleitung modifizieren wir es aber leicht. Zunächst müssen drei benötigte Abhängigkeiten installiert werden:

  pacman -Sy arch-install-scripts expect archlinuxarm-keyring
  

Das modifizierte mkimage-arch.sh trägt nun den Namen mkimage-aarch64.sh und sieht wie folgt aus:

  #!/usr/bin/env bash
  # Generate a minimal filesystem for archlinux and load it into the local
  # docker as "archlinux"
  # requires root
  set -e

  hash pacstrap &>/dev/null || {
    echo "Could not find pacstrap. Run pacman -Sy arch-install-scripts"
    exit 1
  }

  hash expect &>/dev/null || {
    echo "Could not find expect. Run pacman -Sy expect"
    exit 1
  }


  export LANG="C.UTF-8"

  ROOTFS=/var/lib/machines/alarm64
  mkdir -p $ROOTFS
  chmod 755 $ROOTFS

  # packages to ignore for space savings
  PKGIGNORE=(
      cryptsetup
      device-mapper
      dhcpcd
      iproute2
      jfsutils
      linux
      lvm2
      man-db
      man-pages
      mdadm
      nano
      netctl
      openresolv
      pciutils
      pcmciautils
      reiserfsprogs
      s-nail
      systemd-sysvcompat
      usbutils
      vi
      xfsprogs
  )
  IFS=','
  PKGIGNORE="${PKGIGNORE[*]}"
  unset IFS

  case "$(uname -m)" in
    aarch64)
      if pacman -Q archlinuxarm-keyring >/dev/null 2>&1; then
        pacman-key --init
        pacman-key --populate archlinuxarm
      else
        echo "Could not find archlinuxarm-keyring. Please, install it and run pacman-key --populate archlinuxarm"
        exit 1
      fi
      PACMAN_CONF='./mkimage-aarch64-pacman.conf'
      PACMAN_MIRRORLIST='Server = http://mirror.archlinuxarm.org/$arch/$repo'
      PACMAN_EXTRA_PKGS='archlinuxarm-keyring'
      EXPECT_TIMEOUT=3600
      ARCH_KEYRING=archlinuxarm
      DOCKER_IMAGE_NAME=archlinuxarm
      ;;
    *)
      PACMAN_CONF='./mkimage-arch-pacman.conf'
      PACMAN_MIRRORLIST='Server = https://mirrors.kernel.org/archlinux/$repo/os/$arch'
      PACMAN_EXTRA_PKGS=''
      EXPECT_TIMEOUT=60
      ARCH_KEYRING=archlinux
      DOCKER_IMAGE_NAME=archlinux
      ;;
  esac

  export PACMAN_MIRRORLIST

  expect <<EOF
    set send_slow {1 .1}
    proc send {ignore arg} {
      sleep .1
      exp_send -s -- \$arg
    }
    set timeout $EXPECT_TIMEOUT

    spawn pacstrap -C $PACMAN_CONF -c -d -G -i $ROOTFS base haveged $PACMAN_EXTRA_PKGS --ignore $PKGIGNORE
    expect {
      -exact "anyway? \[Y/n\] " { send -- "n\r"; exp_continue }
      -exact "(default=all): " { send -- "\r"; exp_continue }
      -exact "installation? \[Y/n\]" { send -- "y\r"; exp_continue }
    }
  EOF

  arch-chroot $ROOTFS /bin/sh -c 'rm -r /usr/share/man/*'
  arch-chroot $ROOTFS /bin/sh -c "haveged -w 1024; pacman-key --init; pkill haveged; pacman -Rs --noconfirm haveged; pacman-key --populate $ARCH_KEYRING; pkill gpg-agent"
  arch-chroot $ROOTFS /bin/sh -c "ln -s /usr/share/zoneinfo/UTC /etc/localtime"
  echo 'de_DE.UTF-8 UTF-8' > $ROOTFS/etc/locale.gen
  arch-chroot $ROOTFS locale-gen
  arch-chroot $ROOTFS /bin/sh -c 'echo $PACMAN_MIRRORLIST > /etc/pacman.d/mirrorlist'

  # udev doesn't work in containers, rebuild /dev
  DEV=$ROOTFS/dev
  rm -rf $DEV
  mkdir -p $DEV
  mknod -m 666 $DEV/null c 1 3
  mknod -m 666 $DEV/zero c 1 5
  mknod -m 666 $DEV/random c 1 8
  mknod -m 666 $DEV/urandom c 1 9
  mkdir -m 755 $DEV/pts
  mkdir -m 1777 $DEV/shm
  mknod -m 666 $DEV/tty c 5 0
  mknod -m 600 $DEV/console c 5 1
  mknod -m 666 $DEV/tty0 c 4 0
  mknod -m 666 $DEV/full c 1 7
  mknod -m 600 $DEV/initctl p
  mknod -m 666 $DEV/ptmx c 5 2
  ln -sf /proc/self/fd $DEV/fd
  

Die aktuelle Konfiguration von pacman wird ins aktuelle Verzeichnis kopiert, um die Einstellungen vom Hostsystem zu übernehmen:

    cp /etc/pacman.conf ./mkimage-aarch64-pacman.conf
  

Danach kann das Wurzeldateisystem erstellt werden:

    chmod u+x mkimage-aarch64.sh
    LC_ALL=C ./mkimage-aarch64.sh
  

systemd-nspawn

Das neue Wurzeldateisystem wurde in /var/lib/machines/alarm64/. Das bedeutet, dass der Name des Containers alarm64 ist. Mittels -M Option kann der Container nun gestartet werden:

  systemd-nspawn -M alarm64
  

Nun befindet man sich im Container:

  [root@alarm ~]# systemd-nspawn -M alarm64
  Spawning container alarm64 on /var/lib/machines/alarm64.
  Press ^] three times within 1s to kill container.
  [root@alarm64 ~]#
  

Die Netzwerkeinstellungen werden vom Hostsystem übernommen - ein ping sollte also funktionieren:

  [root@alarm64 ~]# ping schweter.eu
  PING schweter.eu (185.11.136.206) 56(84) bytes of data.
  64 bytes from schweter.eu (185.11.136.206): icmp_seq=1 ttl=55 time=33.1 ms
  

systemd in Container

Es ist darüberhinaus möglich, systemd im erzeugten Container laufen zu lassen. Dazu wird vorab ein Rootpasswort gesetzt und ein neuer (unprivilegierter) Benutzer erstellt:

  [root@alarm64 ~]# passwd
  Enter new UNIX password:
  Retype new UNIX password:
  passwd: password updated successfully
  [root@alarm64 ~]# useradd -m -g users -s /bin/bash stefan
  [root@alarm64 ~]# passwd stefan
  Enter new UNIX password:
  Retype new UNIX password:
  passwd: password updated successfully
  

Nun kann systemd im Container installiert werden:

  [root@alarm64 ~]# pacman -Sy systemd
  :: Synchronizing package databases...
   core is up to date
   extra is up to date
   community is up to date
   alarm is up to date
   aur is up to date
  resolving dependencies...
  looking for conflicting packages...

  Packages (11) dbus-1.10.8-1  hwids-20160306-1  iptables-1.6.0-1  kbd-2.0.3-1
                kmod-22-1  libdbus-1.10.8-1  libelf-0.166-1  libmnl-1.0.3-2
                libnftnl-1.0.5-1  libseccomp-2.3.1-1  systemd-229-3

  Total Download Size:    6.84 MiB
  Total Installed Size:  39.02 MiB

  :: Proceed with installation? [Y/n] Y
  :: Retrieving packages...
   libdbus-1.10.8-1-aa...   113.8 KiB  78.5K/s 00:01 [######################] 100%
   dbus-1.10.8-1-aarch64    296.2 KiB   673K/s 00:00 [######################] 100%
   iptables-1.6.0-1-aa...   262.0 KiB   624K/s 00:00 [######################] 100%
   kbd-2.0.3-1-aarch64     1113.4 KiB   659K/s 00:02 [######################] 100%
   kmod-22-1-aarch64         96.0 KiB   600K/s 00:00 [######################] 100%
   hwids-20160306-1-any     326.1 KiB   627K/s 00:01 [######################] 100%
   libelf-0.166-1-aarch64   306.0 KiB   638K/s 00:00 [######################] 100%
   libseccomp-2.3.1-1-...    60.9 KiB   468K/s 00:00 [######################] 100%
   systemd-229-3-aarch64      4.3 MiB   666K/s 00:07 [######################] 100%
   libmnl-1.0.3-2-aarch64     8.0 KiB   802K/s 00:00 [######################] 100%
   libnftnl-1.0.5-1-aa...    39.5 KiB   658K/s 00:00 [######################] 100%
  (11/11) checking keys in keyring                   [######################] 100%
  (11/11) checking package integrity                 [######################] 100%
  (11/11) loading package files                      [######################] 100%
  (11/11) checking for file conflicts                [######################] 100%
  (11/11) checking available disk space              [######################] 100%
  :: Processing package changes...
  ( 1/11) installing libdbus                         [######################] 100%
  ( 2/11) installing dbus                            [######################] 100%
  Optional dependencies for dbus
      libx11: dbus-launch support
  ( 3/11) installing libmnl                          [######################] 100%
  ( 4/11) installing libnftnl                        [######################] 100%
  ( 5/11) installing iptables                        [######################] 100%
  ( 6/11) installing kbd                             [######################] 100%
  ( 7/11) installing kmod                            [######################] 100%
  ( 8/11) installing hwids                           [######################] 100%
  ( 9/11) installing libelf                          [######################] 100%
  (10/11) installing libseccomp                      [######################] 100%
  (11/11) installing systemd                         [######################] 100%
  Initializing machine ID from random generator.
  Creating group systemd-journal-remote with gid 999.
  Creating user systemd-journal-remote (systemd Journal Remote) with uid 999 and gid 999.
  Creating group systemd-journal-upload with gid 998.
  Creating user systemd-journal-upload (systemd Journal Upload) with uid 998 and gid 998.
  Creating group systemd-coredump with gid 997.
  Creating user systemd-coredump (systemd Core Dumper) with uid 997 and gid 997.
  Created symlink /etc/systemd/system/getty.target.wants/getty@tty1.service, pointing to /usr/lib/systemd/system/getty@.service.
  Created symlink /etc/systemd/system/multi-user.target.wants/remote-fs.target, pointing to /usr/lib/systemd/system/remote-fs.target.
  :: Append 'init=/usr/lib/systemd/systemd' to your kernel command line in your
     bootloader to replace sysvinit with systemd, or install systemd-sysvcompat
  Optional dependencies for systemd
      cryptsetup: required for encrypted block devices
      libmicrohttpd: remote journald capabilities
      quota-tools: kernel-level quota management
      systemd-sysvcompat: symlink package to provide sysvinit binaries
      polkit: allow administration as unprivileged user
  

Der Container kann mit STRG+D verlassen werden. Als nächstes wird der Container mit der -b Option gebootet:

  [root@alarm ~]# systemd-nspawn -M alarm64 -b
  Spawning container alarm64 on /var/lib/machines/alarm64.
  Press ^] three times within 1s to kill container.
  systemd 229 running in system mode. (+PAM -AUDIT -SELINUX -IMA -APPARMOR +SMACK -SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN)
  Detected virtualization systemd-nspawn.
  Detected architecture arm64.

  Welcome to Arch Linux ARM!

  [  OK  ] Reached target Encrypted Volumes.
  [  OK  ] Listening on Journal Socket.
  [  OK  ] Created slice System Slice.
           Starting Remount Root and Kernel File Systems...
  [  OK  ] Created slice system-getty.slice.
  [  OK  ] Started Dispatch Password Requests to Console Directory Watch.
  [  OK  ] Started Forward Password Requests to Wall Directory Watch.
  [  OK  ] Reached target Swap.
  [  OK  ] Listening on Journal Socket (/dev/log).
  [  OK  ] Created slice User and Session Slice.
  [  OK  ] Reached target Slices.
           Mounting POSIX Message Queue File System...
  [  OK  ] Listening on /dev/initctl Compatibility Named Pipe.
  [  OK  ] Listening on Process Core Dump Socket.
  [  OK  ] Reached target Remote File Systems.
  [  OK  ] Reached target Paths.
           Mounting Huge Pages File System...
           Starting Journal Service...
  [  OK  ] Mounted Huge Pages File System.
  [  OK  ] Mounted POSIX Message Queue File System.
  [  OK  ] Started Remount Root and Kernel File Systems.
           Starting Rebuild Hardware Database...
           Starting Rebuild Dynamic Linker Cache...
           Starting Create System Users...
           Starting Load/Save Random Seed...
  [  OK  ] Started Load/Save Random Seed.
  [  OK  ] Started Create System Users.
  [  OK  ] Reached target Local File Systems (Pre).
  [  OK  ] Reached target Local File Systems.
           Starting Rebuild Journal Catalog...
  [  OK  ] Started Rebuild Dynamic Linker Cache.
  [  OK  ] Started Rebuild Journal Catalog.
  [  OK  ] Started Journal Service.
           Starting Flush Journal to Persistent Storage...
  [  OK  ] Started Flush Journal to Persistent Storage.
           Starting Create Volatile Files and Directories...
  [  OK  ] Started Create Volatile Files and Directories.
           Starting Update UTMP about System Boot/Shutdown...
  [  OK  ] Started Update UTMP about System Boot/Shutdown.
  [  OK  ] Started Rebuild Hardware Database.
           Starting Update is Completed...
  [  OK  ] Started Update is Completed.
  [  OK  ] Reached target System Initialization.
  [  OK  ] Started Daily verification of password and group files.
  [  OK  ] Listening on D-Bus System Message Bus Socket.
  [  OK  ] Reached target Sockets.
  [  OK  ] Reached target Basic System.
           Starting Login Service...
  [  OK  ] Started Daily Cleanup of Temporary Directories.
  [  OK  ] Started Daily rotation of log files.
  [  OK  ] Reached target Timers.
           Starting Permit User Sessions...
  [  OK  ] Started D-Bus System Message Bus.
  [  OK  ] Started Permit User Sessions.
  [  OK  ] Started Console Getty.
  [  OK  ] Reached target Login Prompts.
  [  OK  ] Started Login Service.
  [  OK  ] Reached target Multi-User System.
  [  OK  ] Reached target Graphical Interface.

  Arch Linux 3.14.29-21-ARCH (console)

  alarm64 login:
  

Wenn alles geklappt hat, meldet sich die Loginaufforderung und man kann sich mit dem vorher erstellten, unprivilegierten Benutzer anmelden.

Quellen

Historie