User Mode Linux

Από Κοινότητα Ελεύθερου Λογισμικού ΕΜΠ
Μετάβαση σε: πλοήγηση, αναζήτηση

Θα χρησιμοποιήσουμε το User Mode Linux (UML) για να τρέξουμε ένα πλήρες Linux σύστημα (guest) ως ένα σύνολο διεργασιών του βασικού μας συστήματος. Εφαρμογές αρκετές, ενδεικτικά:

  • Πολλοί virtual servers στο ίδιο φυσικό σύστημα, απομονωμένοι μεταξύ τους.
  • Ευκολότερο και ασφαλέστερο kernel (και όχι μόνο) development και debugging.
  • Μπορούμε να αποκτήσουμε ένα ολόκληρο δίκτυο για δοκιμές με έναν υπολογιστή.

Το User Mode Linux δεν είναι η μόνη virtualization τεχνική. Άλλες ελεύθερες λύσεις που δεν μας περιορίζουν σε Linux guests είναι:

  • Το KVM (Kernel Virtual Machine) που μπαίνει στον 2.6.20 πυρήνα και χρησιμοποιεί τα virtualization extensions τελευταίων επεξεργαστών (AMD-V, Intel VT-X).
  • To Xen, το οποίο χρησιμοποιεί Paravirtualization. Τα λειτουργικά συστήματα που τρέχουμε πρέπει να γίνουν port σε ένα hypercall ABI του ΧΕΝ, ενώ αμετάβλητα λειτουργικά (ακόμα και Windows) μπορούν πλέον να τρέξουν με την βοήθεια των virtualization extensions.
  • Το Virtualbox, μια έκδοση του οποίου απελευθερώθηκε πολύ πρόσφατα.

Όσα διαβάζετε εδώ έχουν δοκιμαστεί με Slackware host και guest συστήματα με πυρήνα 2.6.19.2 αλλά προφανώς μπορούν να εφαρμοστούν σε οποιαδήποτε διανομή. Το μόνο που αλλάζει είναι ο τρόπος δημιουργίας του image για το guest σύστημα.

Πυρήνες

To UML ζει και αναπτύσσεται πλέον στον vanilla πυρήνα και δεν χρειαζόμαστε εξωτερικά patches.

Στον host πυρήνα πιθανόν να μην χρειάζεται καμία παρέμβαση. Παλαιότερα χρειαζόταν patch για να τρέξουμε το UML σε skas mode, να τρέχουν δηλαδή οι διεργασίες του guest συστήματος σε διαφορετικό address space από τον guest πυρήνα. (TODO: τι διαφορά έχει το skas3;). Σιγουρευτείτε ότι στις "Networking Options" είναι επιλεγμένα τα "IP Tunneling" και 802.11d Ethernet Bridging". Στο "Network device dupport", επιλέξτε το "Universal TUN/TAP device driver support". Αυτά θα μας χρειαστούν για τη δικτύωση του guest με τον host (αν θέλετε να παίξετε και με το iptables μάλλον ξέρετε τι πρέπει να επιλέξετε).

Χρειαζόμαστε έναν guest πυρήνα. Σε ένα νέο αντίγραφο του directory με το source του πυρήνα (υποθέτω ξέρετε που θα το βρείτε) για να μην μπλέξουμε με τον host πυρήνα:

host$ make mrproper ARCH=um
host$ make defconfig ARCH=um
host$ make linux ARCH=um
host$ make modules ARCH=um

Προσοχή στο ARCH=um, δεν χτίζουμε έναν οποιονδήποτε x86 πυρήνα. Το make defconfig Θα δημιουργήσετε ένα λογικό config, δεδομένου ότι το εικονικό hardware είναι ίδιο για όλους. Αν θέλετε να το παραμετροποιήσετε make menuconfig ARCH=um. Φροντίστε να είναι built-in (και όχι ως module) η υποστήριξη του file system που θα χρησιμοποιήσετε στον guest.

Ο guest πυρήνας που θα προκύψει (στο top-level directory του source tree) είναι ένα ELF εκτελέσιμο σαν όλα τα άλλα, δείτε τις επιλογές του με

host$ ./linux --help

Δημιουργία image

με το Qemu

Δημιουργούμε το image (έστω 1GB) και εγκαθιστούμε το guest σύστημα με το CD/DVD της διανομής ή το αντίστοιχο ISO (έστω το slackware-11.0-install-dvd.iso):

host$ qemu-img create qemudisk.img 700M
host$ qemu -hda qemudisk.img -cdrom slackware-11.0-install-dvd.iso -bood d

εγκαθιστούμε κανονικά τη διανομή, χρησιμοποιώντας ένα μόνο partition (είναι δυνατόν τα images που χρησιμοποιούμε με το UML να έχουν πολλά partitions). Έχουμε δημιουργήσει το image ενός πλήρους δίσκου, με το MBR, το partition table κλπ, απομονώνουμε το file system που μας ενδιαφέρει:

host$ dd if=qemudisk.img of=slack11.img bs=512 skip=63

με την οποία παρακάμπτουμε τους πρώτους 63 sectors (των 512 bytes) και μένει το επιθυμητό partition στο slack11.img.

με πακέτα του Slackware

Δημιουργούμε με το dd ένα image, έστω του 1GB:

host$ dd if=/dev/zero of=slack11.img bs=1024 seek=1048576 count=0

Δημιουργούμε ένα file system στο image. Για ReiserFS:

host$ /sbin/mkfs.reiserfs -f slack11.img

Κάνουμε mount το image σε κάποιο directory (έστω slackroot). Με πυρήνα που υποστηρίζει loopback devices (φορτωμένο το module loop):

host# mount -o loop slack11.img slackroot

Με την επιλογή -root του installpkg ή δίνοντας την κατάλληλη τιμή στην μεταβλητή περιβάλλοντος ROOT εγκαθιστούμε τα επιθυμητά πακέτα στο image. Για παράδειγμα:

host# export ROOT=`pwd`/slackroot
host# installpkg slackware/slackware-11.0/slackware/a/aaa_base-11.0.0-noarch-2.tgz

Για server εγκατάσταση μάλλον θα χρειαστείτε πακέτα από τα directories a, ap, d και n.

Booting

Το image δεν είναι έτοιμο για χρήση. Πρέπει να εγκαταστήσουμε τα modules του guest πυρήνα. Από το directory των kernel sources:

host# make modules_install INSTALL_MOD_PATH=$ROOT

όπου $ROOT το mounted guest file system (όπως παραπάνω).

Είναι απαραίτητο να δημιουργήσουμε με το χέρι στατικά block device files για το image που έχουμε δημιουργήσει, γιατί το / πρέπει να γίνει mount rw πριν τρέξει το udev και αναλάβει να γεμίσει δυναμικά το /dev. Στην περίπτωση που χρησιμοποιούμε ένα μόνο image με ένα partition:

host# mknod $ROOT/dev/ubda b 98 0

Τα block devices στο UML ονομάζονται udba, udbb κλπ ή συνώνυμα udb1, udb2 κλπ. Αν κάποιο image, έστω το ubda, έχει περισσότερα του ενός partitions αυτά θα ονομάζονται ubda1, ubda2...

Αλλάζουμε στο /etc/fstab του guest τη γραμμή που αντιστοιχεί στο / :

/dev/ubda        /                reiserfs    defaults         1   1

Τρέχουμε τον guest πυρήνα με παράμετρο το image που έχουμε δημιουργήσει:

host$ ./linux ubda=slack11.img

τα μηνύματα του guest πυρήνα εμφανίζονται στο τερματικό και αν όλα πάνε καλά ανοίγουν xterm που αντιστοιχούν στα tty και μπορούμε να κάνουμε login. Μπορούμε να αφήσουμε ένα ή και κανένα tty απενεργοποιώντας τα υπόλοιπα στο /etc/inittab του guest:

c1:1235:respawn:/sbin/agetty 38400 tty1 linux
#c2:1235:respawn:/sbin/agetty 38400 tty2 linux

Networking

Θα χρησιμοποιήσουμε TUN/TAP για να δικτυώσουμε τον guest με τον host. Θα δημιουργήσουμε το interface tap0 στον host, το οποίο και θα είναι δικτυωμένο με το eth0 του guest. Εγκαθιστούμε τα uml-utilities (κατεβάστε τα από το [1]) τα οποία περιλαμβάνουν το εργαλείο tunctl που θα χρειαστούμε. Στο host σύστημα δίνουμε τις εντολές:

host# modprobe tun
host# tunctl -u username
host# ifconfig tap0 inet 10.0.1.1

με τις οποίες φορτώνουμε το tun module του πυρήνα, δημιουργούμε το tap0 και του δίνουμε την IP 10.0.1.1.

Ξεκινάμε το guest σύστημα κάπως έτσι:

host$ ./linux ubda=slack11.img eth0=tuntap,,,10.0.1.1

εδώ με τα ,, παραλείψαμε τις επιλογές για το device και τη MAC address. Όταν bootάρει δίνουμε:

guest# ifconfig eth0 inet 10.0.1.2

με την οποία ο guest αποκτά την IP 10.0.1.2 . Το

guest$ ping 10.0.1.1

ping 10.0.1.2 από τον host) θα μας πείσει ότι τα δύο συστήματα είναι δικτυωμένα. Για να μην απαιτείται το ifconfig μετά από κάθε boot του guest, οι αντίστοιχες γραμμές στο /etc/rc.d/rc.inet1.conf μπορούν να γίνουν

# Config information for eth0:
IPADDR[0]="10.0.1.2"
NETMASK[0]="255.255.255.0"
USE_DHCP[0]="no"
DHCP_HOSTNAME[0]=""

Αντίστοιχα μπορούμε να πειράξουμε και τα init scripts του host για να μην απαιτείται ρύθμιση του δικτύου.

Το TUN/TAP δεν είναι η μόνη επιλογή για τη δικτύωση με το UML, περισσότερες επιλογές θα βρείτε στο [2].

Σημειώσεις

  • Τα COW (Copy On Write) images μας επιτρέπουν να ανοίξουμε μόνο για ανάγνωση το image του guest και οι αλλαγές να αποθηκεύονται στο cow αρχείο. Ξεκινούμε το guest σύστημα με την επιλογή ubd0=cow,file.img. Μπορούμε να τρέχουμε διαφορετικά στιγμιότυπα του UML με το ίδιο image και διαφορετικά COW ή να πειραματιστούμε με τον guest και οι αλλαγές να είναι αναστρέψιμες. Το εργαλείο uml_moo μας επιτρέπει να ενσωματώσουμε τις αλλαγές που έχουμε κάνει από το COW στο image. [3]
  • Το software πάντα έχει bugs και έχουν υπάρξει κενά ασφαλείας που επιτρέπουν στον χρήστη ενός UML να αποκτήσει πρόσβαση στον host [4]. Μπορούμε να αυξήσουμε το επίπεδο ασφάλειας, για παράδειγμα χρησιμοποιώντας έναν χρήστη στον host ειδικά για το UML ή τρέχοντας το UML chrooted στον host [5].