Το προφίλ μας στο Google Plus
0

Διαχείριση εικονικών τοπικών δικτύων στον κόσμο του libvirt

Στο τεύχος 060 του deltaHacker δείξαμε μεταξύ άλλων πώς φτιάχνουμε και κλωνοποιούμε QEMU/KVM VMs, εργαζόμενοι αποκλειστικά από τη γραμμή εντολών. Είναι ώρα να ασχοληθούμε και με τα εικονικά τοπικά δίκτυα, παραμένοντας βεβαίως στην αγαπημένη μας text console.

Γιατί όμως να προτιμήσουμε την κονσόλα, όταν διαθέτουμε εύχρηστες εφαρμογές για το περιβάλλον γραφικών, όπως, π.χ., είναι ο Virtual Machine Manager; Όπως φανταζόσαστε, υπάρχουν περισσότεροι από ένας λόγοι. Ίσως ο VM host να είναι ένα απομακρυσμένο μηχάνημα, χωρίς GUI. Ίσως πάλι σχεδιάζουμε να γράψουμε μερικά scripts για τη γρήγορη δημιουργία εικονικών εργαστηρίων για development ή για τις ανάγκες μιας παρουσίασης. Είναι επίσης πιθανό να επιδιώκουμε την αξιολόγηση ενός cluster, συγκεκριμένων υπηρεσιών ή μιας νέας τεχνολογίας πριν από το deployment σε πραγματικό hardware. Ό,τι κι αν ισχύει, η εργασία από την text console έχει μοναδικά πλεονεκτήματα τα οποία απουσιάζουν από το όποιο GUI.

Ξεκίνημα με απαραίτητη παρένθεση
Πριν περάσουμε στο προκείμενο αξίζει να αναφερθούμε εν τάχει σε συγκεκριμένους όρους, τους οποίους πολύ συχνά χρησιμοποιούμε χωρίς όμως να έχουμε ορίσει επακριβώς. Προς αποφυγή παρερμηνειών, λοιπόν, σκεφτόμαστε ότι καλό θα ήταν να συζητήσουμε λίγο περί KVM, QEMU και libvirt.

  • Το KVM (Kernel-based Virtual Machine) είναι μια τεχνολογία που επιτρέπει στον πυρήνα του Linux να λειτουργεί ως hypervizor, μ’ άλλα λόγια να είναι ικανός για τη φιλοξενία εικονικών μηχανών. Από την έκδοση 2.6.20 του πυρήνα, το KVM αποτελεί υποσύστημά του. Διατίθεται επίσης ως loadable module για τα FreeBSD και illumos. Το KVM απαιτεί από τον φυσικό επεξεργαστή να παρέχει τα λεγόμενα hardware virtualization extensions. Αν και αρχικά υποστήριζε μόνο x86/x86-64 CPUs (πάντα με virtualization extensions), σταδιακά άρχισε να υποστηρίζει κι άλλες αρχιτεκτονικές επεξεργαστών, όπως, π.χ., PowerPC και ARM. Οι εικονικές μηχανές που βασίζονται στο KVM μπορούν να τρέχουν μια ευρεία γκάμα λειτουργικών συστημάτων, με τα Windows, Linux, BSD και OS X να αποτελούν τους συνήθεις υπόπτους. Αξίζει να υπογραμμίσουμε ότι το KVM από μόνο του δεν υλοποιεί κάποιου είδους εξομοίωση. Αντίθετα, σε εφαρμογές του userspace παρέχει το ειδικό αρχείο συσκευής /dev/kvm, ώστε αυτές να είναι σε θέση να δημιουργούν εικονικές μηχανές και, το σημαντικότερο, να τις τρέχουν αποδοτικά.

  • Το QEMU (Quick EMUlator) είναι μια εφαρμογή δημιουργίας και διαχείρισης εικονικών μηχανών, η οποία κάνει χρήση του /dev/kvm χωρίς όμως να το απαιτεί. Αναλυτικότερα, το QEMU είναι ικανό να εξομοιώνει πλήρως το hardware ενός υπολογιστή κι αυτός με τη σειρά του είναι ικανός να τρέχει μια σειρά λειτουργικών συστημάτων. Όταν το QEMU εντοπίζει το /dev/kvm, τότε πρόθυμα το χρησιμοποιεί και οι σχετικές εικονικές μηχανές τρέχουν με ταχύτητες παραπλήσιες του φυσικού υπολογιστή που τις φιλοξενεί. Κάθε φορά, λοιπόν, που γράφουμε QEMU/KVM, ουσιαστικά αναφερόμαστε σε εικονικές μηχανές QEMU οι οποίες φιλοξενούνται σε υπολογιστή που υποστηρίζει την τεχνολογία του KVM.

  • Το δε libvirt είναι κάτι σαν εργαλειοθήκη για τη διαχείριση διαφορετικών virtualization platforms. Παρέχει ένα API σε C και bindings για γλώσσες όπως Python, Ruby και JavaScript. Επίσης, μία υπηρεσία (daemon) καθώς κι εργαλεία διαχείρισης. Χάρη στο libvirt οι προγραμματιστές είναι σε θέση ν’ αναπτύσσουν εφαρμογές χωρίς να νοιάζονται για το ποιος είναι ο hypervizor στο παρασκήνιο. Επειδή το libvirt ξέρει πώς να μιλά σε QEMU/KVM, VMware, VirtualBox, bhyve κι άλλες πλατφόρμες, μια εφαρμογή που χρησιμοποιεί το libvirt API είναι σε θέση να λέει ξεκίνα την τάδε μηχανή, δώσε μου όλες τις ενεργές μηχανές, διπλασίασε τη μνήμη αυτής της μηχανής παραπέρα, πάρε ένα snapshot, πρόσθεσε έναν δίσκο κ.ο.κ., κι από εκεί και πέρα να μη νοιάζεται για τις λεπτομέρειες της υλοποίησης. Και δεν νοιάζεται διότι κάθε φορά που τα λέει με το libvirt API, είναι μετά ευθύνη του τελευταίου να πραγματοποιήσει τις όποιες επιθυμίες της — ή τουλάχιστον να προσπαθήσει κι αν αποτύχει να αναφέρει το λόγο. Μερικά παραδείγματα εφαρμογών που χρησιμοποιούν το libvirt API είναι ο Virtual Machine Manager, το virsh (συμπεριλαμβάνεται στο βασικό πακέτο του libvirt, δείτε εδώ), καθώς και το virt-clone (δείτε κι εδώ).

Σε πολύ λίγο θα καταφύγουμε στο εργαλείο virsh, προκειμένου να δούμε πώς μας βοηθά στη δημιουργία αλλά και στη διαχείριση δικτύων για εικονικές μηχανές.

Δύο μέθοδοι δικτύωσης
Ανεξαρτήτως του hypervizor, για το libvirt υπάρχουν δύο βασικές μέθοδοι δικτύωσης των εικονικών μηχανών: Bridged Networking και NAT Forwarding. Καθένα από τα δύο αυτά networking setups έχει τα υπέρ και τα κατά του.

Bridged Networking. Μέσω μίας ή περισσοτέρων φυσικών καρτών Ethernet, τα VMs (guests) με δικτύωση του είδους βλέπουν απευθείας το LAN εντός του οποίου βρίσκεται το host computer. (Ακριβέστερα, το βλέπουν μέσω του Linux host bridge. Περί bridging διαβάστε περισσότερα εδώ.) Το συγκεκριμένο setup προτείνεται για virtualization servers κι όχι, π.χ., για laptops, τα οποία συνήθως μετακινούνται από δίκτυο σε δίκτυο. Οι μηχανές με bridged networking παρουσιάζουν τις καλύτερες δυνατές δικτυακές επιδόσεις, ενώ είναι κι εύκολα προσβάσιμες από άλλα (εικονικά ή φυσικά) μηχανήματα. Αν όμως το host computer βγαίνει στον έξω κόσμο μέσω ασύρματης σύνδεσης, το αντίστοιχο wireless interface δεν είναι δυνατόν να συμμετέχει σε ένα Linux host bridge. Σε περιπτώσεις σαν αυτή δεν μπορούμε να χρησιμοποιήσουμε Bridged Networking για τα guests. Ευτυχώς, υπάρχει και το NAT Forwarding.

Αυτόματη δημιουργία Linux host bridge σε υπολογιστή με openSUSE, με τη βοήθεια του YaST2.

Η δημιουργία Linux host bridge για τη δικτύωση των QEMU/KVM VMs επιτυγχάνεται με διαφορετικό τρόπο από διανομή σε διανομή. Αν πάντως το host OS του υπολογιστή μας είναι το openSUSE κι εγκαθιστούμε το λογισμικό για την υποστήριξη του KVM με τη βοήθεια του YaST2, μπορούμε να ζητήσουμε την αυτόματη δημιουργία bridge.

NAT Forwarding. Μετά την εγκατάσταση του libvirt και φυσικά την εκκίνηση της αντίστοιχης υπηρεσίας, στο host computer υπάρχει έτοιμο ένα εικονικό network switch. Τα VMs που συνδέονται πάνω του έχουν τις δικές τους, εσωτερικές διευθύνσεις IP. Χάρη στην τεχνική του NAT (Network Address Translation), όταν βγαίνουν στον έξω κόσμο εμφανίζονται με το δημόσιο IP του host computer. Προφανώς, ο συγκεκριμένος τρόπος δικτύωσης είναι ό,τι πρέπει για hosts που είτε αλλάζουν συνέχεια δίκτυο είτε συνδέονται στο Internet μέσω wireless interface. Αλλά αυτή η ευελιξία ή φορητότητα, αν θέλετε, έχει και το κόστος της: εικονικοί ή φυσικοί υπολογιστές που είναι εξωτερικοί ως προς τον virtualization host, δεν είναι σε θέση να ξεκινούν συνδέσεις με VMs πίσω από το εικονικό switch. Μόνος τρόπος για να το πετυχαίνουν είναι με την εισαγωγή κανόνων port forwarding στο firewall του host. Κάτι τέτοιο, όμως, αυξάνει την πολυπλοκότητα του network setup για τον host και, όπως γίνεται φανερό, από ένα σημείο κι έπειτα δεν αξίζει να έχουμε server VMs πίσω από εικονικά network switches.

To προκαθορισμένο εικονικό τοπικό δίκτυο
Αναφέραμε ότι με την εκκίνηση της υπηρεσίας του libvirt, στο host computer υπάρχει έτοιμο ένα εικονικό switch. Το host OS συνδέεται πάνω του μέσω του network bridge interface με όνομα virbr0. Στο πλαίσιο της παρουσίασής μας δουλεύουμε σε ένα laptop με openSUSE Leap 42.3 (hostname: dalvik), οπότε δείτε τώρα το virbr0 μέσα από το προγραμματάκι ip:

[cvar AT dalvík] ~> ip a show virbr0
4: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue [...]
    link/ether 52:54:00:f6:ff:9c brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
        valid_lft forever preferred_lft forever

Η διεύθυνση IP του virbr0 είναι 192.168.122.1, κι αυτή είναι η διεύθυνση του router για τις εικονικές μηχανές πίσω από το switch. Τώρα, όλα τα εικονικά τοπικά δίκτυα που ορίζουν τα network switches του libvirt –αρχικά ξεκινάμε με μόνο ένα τέτοιο switch–, τα βλέπουμε ανά πάσα στιγμή με τη βοήθεια του εργαλείου virsh:

[cvar AT dalvík] ~> virsh net-list
 Name                 State      Autostart     Persistent
----------------------------------------------------------
 default              active     yes           yes

Καμία έκπληξη εδώ: έχουμε ένα μόνο εικονικό δίκτυο με όνομα default, το οποίο είναι ενεργό (State = active), μη-εφήμερο (Persistent = yes, δηλαδή διατηρείται και μετά από επανεκκίνηση του libvirt), και ρυθμισμένο ώστε να ενεργοποιείται αυτόματα κατά την (επαν)εκκίνηση του libvirt (Autostart = yes). Συνοπτικές πληροφορίες για ένα συγκεκριμένο εικονικό τοπικό δίκτυο, όπως είναι το default που ήδη έχουμε, παίρνουμε κι έτσι:

[cvar AT dalvík] ~> virsh net-info default
Name:           default
UUID:           112ac4cc-79c0-4bc2-ae33-f7e068c15111
Active:         yes
Persistent:     yes
Autostart:      yes
Bridge:         virbr0

Κάθε εικονικό τοπικό δίκτυο στον κόσμο του libvirt ορίζεται από ένα αρχείο XML. Προβάλλοντας το XML του default, παίρνουμε αναλυτικότερες πληροφορίες για το αντίστοιχο δίκτυο. Δείτε πώς ακριβώς βλέπουμε το XML του default:

[cvar AT dalvík] ~> virsh net-dumpxml default
<network>
  <name>default</name>
  <uuid>112ac4cc-79c0-4bc2-ae33-f7e068c15111</uuid>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:f6:ff:9c'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254'/>
    </dhcp>
  </ip>
</network>

Παρατηρήστε ότι παρέχεται δυναμική απόδοση διευθύνσεων IP, ξεκινώντας από την 192.168.122.2 και φτάνοντας έως και την 192.168.122.254. Στην πραγματικότητα, για κάθε εικονικό τοπικό δίκτυο που θέλουμε υπηρεσίες DHCP και DNS, το libvirt ξεκινά ένα κατάλληλα ρυθμισμένο instance του dnsmasq. Πώς βλέπουμε τις αποδόσεις διευθύνσεων IP για όλα τα VMs που βρίσκονται εντός συγκεκριμένου εικονικού τοπικού δικτύου; Προς το παρόν έχουμε μόνον ένα τέτοιο δίκτυο, το default. Έχουμε επίσης ξεκινήσει ένα VM, το qleap, το οποίο είναι συνδεδεμένο πάνω στο virbr0 switch. Τη μία και μοναδική απόδοση διεύθυνσης από πλευράς dnsmasq, τη βλέπουμε με τη βοήθεια του virsh:

[cvar AT dalvík] ~> virsh net-dhcp-leases default
Expiry Time         MAC address       [...] IP address        Hostname [...]
----------------------------------------------------------------------------
2017-10-29 10:42:57 52:54:00:45:67:31 [...] 192.168.122.86/24 qleap    [...]

Το VM του παραδείγματός μας, λοιπόν, έχει τη διεύθυνση 192.168.122.86. Με βάση αυτή μπορούμε να φτάνουμε στο qleap από το host computer, π.χ., ξεκινώντας μια σύνδεση SSH:

[cvar AT dalvík] ~> ssh userson@192.168.122.86
Password:
Last login: Sun Oct 29 08:16:22 2017 from 192.168.122.1
Have a lot of fun...
userson@qleap:~> hostname -f
qleap

Προς το παρόν δεν μπορούμε να φτάνουμε στο qleap με βάση το hostname ή το FQDN του (Fully Qualified Domain Name), αλλά λίγο αργότερα θα το τακτοποιήσουμε κι αυτό το θέμα.

Δημιουργία νέου εικονικού τοπικού δικτύου
Αναλόγως του πρότζεκτ πάνω στο οποίο δουλεύουμε, είναι πιθανό να μη θέλουμε το προκαθορισμένο δίκτυο default αλλά να επιθυμούμε τη δημιουργία κάποιου άλλου. Πάντα με τη βοήθεια του εργαλείου virsh, ας δημιουργήσουμε ένα νέο εικονικό τοπικό δίκτυο με όνομα delta, το οποίο εξυπηρετεί το domain delta.is και στα VMs παρέχει υπηρεσίες DHCP και DNS. Το νέο δίκτυο θα υποστηρίζει και NAT forwarding, επομένως τα VMs του θα βγαίνουν στον έξω κόσμο με το δημόσιο IP του host computer. Χρειαζόμαστε ένα αρχείο XML που θα περιγράφει τα χαρακτηριστικά του νέου αυτού δικτύου. Φτιάχνουμε ένα νέο αρχείο με όνομα delta.xml (στην πραγματικότητα δεν έχει σημασία το πώς θα τ’ ονομάσουμε) και με το ακόλουθο περιεχόμενο:

<network>
  <name>delta</name>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <domain name='delta.is' localOnly="yes"/>
  <ip address='10.20.30.254' netmask='255.255.255.0'>
    <dhcp>
      <range start='10.20.30.200' end='10.20.30.253'/>
    </dhcp>
  </ip>
</network>

Παρατηρήστε ότι:

  • το όνομα του νέου δικτύου είναι delta (οδηγία <name>delta</name>)
  • υποστηρίζεται το NAT forwarding (ενότητα <forward mode='nat'> έως </forward>)
  • το domain name για το dnsmasq είναι το delta.is (οδηγία <domain name='delta.is' localOnly="yes"/>)
  • εξαιτίας της τιμής που αναθέσαμε στην ιδιότητα localOnly, τα ερωτήματα που αφορούν στο delta.is θα απαντώνται μόνο από τον DNS server του domain και δεν θα προωθούνται σε άλλους name servers, πιο ψηλά στην ιεραρχία του DNS (το domain delta.is το χρησιμοποιούμε αυθαίρετα, χωρίς καν να έχουμε ελέγξει αν υπάρχει στο Internet: αν πράγματι υπάρχει, δεν θέλουμε να απασχολούμε τον name server του με ερωτήματα που τις περισσότερες φορές αφορούν σε τοπικά VMs)
  • για τα VMs του delta η διεύθυνση των router και name server είναι 10.20.30.254, το network mask είναι το 255.255.255.0, ενώ λαμβάνουν δυναμικά διευθύνσεις IP ξεκινώντας από την 10.20.30.200 και φτάνοντας έως και την 10.20.30.253 (ενότητα <ip address='10.20.30.254' netmask='255.255.255.0'> έως </ip>)

Προκειμένου να ορίσουμε το νέο μας δίκτυο, απλά πληκτρολογούμε:

[cvar AT dalvík] ~> virsh net-define delta.xml
Network delta defined from delta.xml

Ωραία, το μήνυμα που επέστρεψε το virsh είναι ενθαρρυντικό. Ας δούμε όλα τα εικονικά τοπικά δίκτυα στο σύστημά μας:

[cvar AT dalvík] ~> virsh net-list
 Name                 State      Autostart     Persistent
----------------------------------------------------------
 default              active     yes           yes

Βλέπουμε μόνο το default κι όχι το delta που μόλις ορίσαμε –κατά τα λεγόμενα του virsh— επιτυχώς. Το νέο δίκτυο είναι πράγματι ορισμένο, αλλά προς το παρόν είναι ανενεργό. Αν θέλουμε το virsh να επιστρέψει όλα τα δίκτυα, ενεργά κι ανενεργά, τότε στην εντολή net-list παρέχουμε και την παράμετρο --all:

[cvar AT dalvík] ~> virsh net-list --all
 Name                 State      Autostart     Persistent
----------------------------------------------------------
 default              active     yes           yes
 delta                inactive   no            yes

Το δίκτυο delta το ενεργοποιούμε πληκτρολογώντας…

[cvar AT dalvík] ~> virsh net-start delta
Network delta started

…και φροντίζουμε ώστε να ξεκινά αυτόματα:

[cvar AT dalvík] ~> virsh net-autostart delta
Network delta marked as autostarted

Δείτε τώρα την έξοδο του virsh net-list, χωρίς την παράμετρο --all:

[cvar AT dalvík] ~> virsh net-list
 Name                 State      Autostart     Persistent
----------------------------------------------------------
 default              active     yes           yes
 delta                active     yes           yes

Πάρα πολύ ωραία. Στην εντολή net-define του virsh δώσαμε το αρχείο delta.xml και με βάση αυτό το εργαλείο παρήγαγε ένα εκτενέστερο αρχείο XML. Δείτε τι εννοούμε:

[cvar AT dalvík] ~> virsh net-dumpxml delta
<network>
  <name>delta</name>
  <uuid>e1a9536a-d185-4c04-ab63-459762232839</uuid>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='virbr1' stp='on' delay='0'/>
  <mac address='52:54:00:12:e1:d7'/>
  <domain name='delta.is' localOnly="yes"/>
  <ip address='10.20.30.254' netmask='255.255.255.0'>
    <dhcp>
      <range start='10.20.30.200' end='10.20.30.253'/>
    </dhcp>
  </ip>
</network>

Αμέσως διαπιστώνουμε ότι το virsh είναι αρκετά έξυπνο, ώστε να δημιουργεί αυτόματα τα ακόλουθα στοιχεία:

  • ένα μοναδικό UUID για το νέο δίκτυο (<uuid>e1a9536a-d185-4c04-ab63-459762232839</uuid>)
  • ένα νέο network bridge interface, το virbr1, για το host OS
  • ένα μοναδικό MAC address για το νέο bridge (<mac address='52:54:00:12:e1:d7'/>)

Ιδού και τα network bridge interfaces των δύο εικονικών τοπικών δικτύων, όπως φαίνονται από το host OS:

[cvar AT dalvík] ~> ip a show
[...]
10: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue [...]
    link/ether 52:54:00:f6:ff:9c brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
       valid_lft forever preferred_lft forever
[...]
17: virbr1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue [...]
    link/ether 52:54:00:12:e1:d7 brd ff:ff:ff:ff:ff:ff
    inet 10.20.30.254/24 brd 10.20.30.255 scope global virbr1
       valid_lft forever preferred_lft forever
[...]

Επιλογή δικτύου κατά τη δημιουργία νέου QEMU/KVM VM
Σε σχετικά άρθρα του τεύχους 060, τα οποία μπορείτε να διαβάσετε εδώ κι εδώ, δείξαμε πώς δημιουργούμε QEMU/KVM VMs από τη γραμμή εντολών. Ουσιαστικά καταφεύγουμε στο εργαλείο virt-install και το δίκτυο στο οποίο θα ανήκει το νέο VM το δίνουμε ως όρισμα στην παράμετρο --network. Για λόγους πληρότητας, ας δούμε άλλο ένα παράδειγμα δημιουργίας VM με guest OS το Fedora 26 Server, το οποίο θα βρίσκεται εντός του δικτύου delta. Αρχικά φτιάχνουμε ένα νέο QCOW2 image μεγέθους 128GiB, το οποίο θα αποτελέσει το δίσκο εγκατάστασης του VM:

[cvar AT dalvík] ~> virsh vol-create-as theQCOW2s \
> --name fedora26.qcow2 --capacity 128G --format qcow2

Το νέο image είναι sparse file (το μέγεθός του δεν είναι 128GiB, απλά αυτό είναι το άνω όριο για τη δυναμική επέκταση του αρχείου), βρίσκεται δε μέσα στο pool με όνομα theQCOW2s. Αμέσως μετά προχωράμε στη δημιουργία του VM:

[cvar AT dalvík] ~> virt-install --name fedora26 \
> --memory 1536 --cpu host --vcpus=2 \
> --network network=delta,model=virtio \
> --disk ~/theQCOW2s/fedora26.qcow2,bus=virtio \
> --location over_there

Το νέο μας VM ονομάζεται fedora26, έχει 1.5GiB μνήμης RAM, δύο εικονικούς επεξεργαστές και συνδέεται στο switch του δικτύου delta. Ενδιαφέρον έχει η παράμετρος --location, με χρήση της οποίας λέμε ότι η εγκατάσταση θα γίνει δικτυακά και συγκεκριμένα από το mirror στο Πανεπιστήμιο της Κρήτης, στη διεύθυνση https://ftp.cc.uoc.gr/pub/linux/fedora/linux/releases/26/Server/x86_64/os (αντικαταστήστε το over_there με τη διεύθυνση που μόλις δώσαμε). Πληκτρολογώντας την παραπάνω εντολή το VM δημιουργείται, ενεργοποιείται και, αφού κατέβουν ορισμένα απαραίτητα αρχεία, ξεκινά η διαδικασία εγκατάστασης του Fedora 26 Server. Μετά την ολοκλήρωσή της, αν όλα έχουν πάει καλά η εντολή virsh net-dhcp-leases delta θα επιστρέψει το DHCP lease του VM:

[cvar AT dalvík] ~> virsh net-dhcp-leases delta
 Expiry Time         MAC address       [...] IP address      Hostname [...]
---------------------------------------------------------------------------
 2017-10-29 17:32:16 52:54:00:ad:7e:49 [...] 10.20.30.200/24 fedora26 [...]

Ας συνδεθούμε για πρώτη φορά από το host computer μέσω SSH, στο λογαριασμό του root:

[cvar AT dalvík] ~> ssh root@10.20.30.200
The authenticity of host '10.20.30.200 (10.20.30.200)' can't be established.
[...]
Are you sure you want to continue connecting (yes/no)? yes
[...]
root@10.20.30.200's password:
[root@fedora26 ~]# hostname -f
fedora26.delta.is

Όπως βλέπετε, το hostname που επιλέξαμε για το VM μας είναι το (καθόλου πρωτότυπο) fedora26. Το δε domain, το οποίο κατά τα αναμενόμενα είναι το delta.is, δεν το δώσαμε εμείς αλλά ελήφθη από το instance του dnsmasq για το εικονικό τοπικό δίκτυο delta.

Αλλαγή δικτύου για υπάρχον QEMU/KVM VM
Είναι πολύ εύκολο να αλλάξουμε το εικονικό τοπικό δίκτυο στο οποίο ανήκει ένα συγκεκριμένο VM. Στο πλαίσιο της παρουσίασής μας, για παράδειγμα, έχουμε το VM με όνομα qleap, από το δίκτυο default. Προκειμένου να το μεταφέρουμε στο δίκτυο delta, φροντίζουμε ώστε το VM να είναι ανενεργό (αν δεν είναι δίνουμε virsh shutdown qleap) και τροποποιούμε το XML του πληκτρολογώντας virsh edit qleap. Το περιεχόμενο του XML θα φορτώσει στον προκαθορισμένο editor και θα εντοπίσουμε τη γραμμή <source network='default'/>. Το μόνο που χρειάζεται ν’ αλλάξουμε είναι το default, το οποίο θα το κάνουμε delta. Αποθηκεύουμε την αλλαγή, εγκαταλείπουμε τον editor κι αν δεν έχουμε εισαγάγει κάποιο συντακτικό λάθος στο XML, το virsh λέει: Domain qleap XML configuration edited. Αν τώρα ξεκινήσουμε το VM (virsh start qleap), μετά από λίγο θα το δούμε κι αυτό στη λίστα με τα DHCP leases για τα VMs εντός του delta:

[cvar AT dalvík] ~> virsh net-dhcp-leases delta
Expiry Time         MAC address       Protocol IP address      Hostname [...]
-----------------------------------------------------------------------------
2017-10-29 20:16:16 52:54:00:45:67:31 [...]    10.20.30.231/24 qleap    [...]
2017-10-29 20:00:37 52:54:00:ad:7e:49 [...]    10.20.30.200/24 fedora26 [...]

Τροποποίηση υπάρχοντος εικονικού τοπικού δικτύου
Τα αρχεία XML των εικονικών τοπικών δικτύων βρίσκονται κάτω από τον κατάλογο /etc/libvirt/qemu/networks:

[cvar AT dalvík] ~> sudo ls -lh /etc/libvirt/qemu/networks
total 8.0K
drwx------ 1 root root  40 Oct 29 12:23 autostart
-rw------- 1 root root 576 Apr  8  2017 default.xml
-rw------- 1 root root 667 Oct 29 12:05 delta.xml

Επιπρόσθετα, για τα δίκτυα που ξεκινούν αυτόματα υπάρχει κι από ένα symbolic link μέσα στον κατάλογο /etc/libvirt/qemu/networks/autostart. Για το σύστημά μας έχουμε δύο δίκτυα, τα default και delta, τα οποία αμφότερα ξεκινούν αυτόματα. Μέσα στο autostart, λοιπόν, θα πρέπει να υπάρχουν δύο links. Πράγματι, έτσι είναι:

[cvar AT dalvík] ~> sudo ls -lh /etc/libvirt/qemu/networks/autostart
total 8.0K
[...] Sep 12 20:32 default.xml -> /etc/libvirt/qemu/networks/default.xml
[...] Oct 29 12:23 delta.xml -> /etc/libvirt/qemu/networks/delta.xml

Τώρα, αν θέλουμε να τροποποιήσουμε τις ιδιότητες ενός συγκεκριμένου δικτύου, τότε δεν επεμβαίνουμε απευθείας στο αντίστοιχο αρχείο XML. Αντίθετα, το τροποποιούμε δίνοντας στο virsh την εντολή net-edit ακολουθούμενη από το όνομα του δικτύου κι όχι από το πλήρες όνομα του αντίστοιχου αρχείου XML. Ως ένα παράδειγμα, ας δούμε πώς λέμε στο στο dnsmasq instance του default να εξυπηρετεί το domain με όνομα local.kvm. Από το host OS ανοίγουμε το XML του δικτύου default:

[cvar AT dalvík] ~> virsh net-edit default

Ανάμεσα σ’ αυτές τις δύο γραμμές…

<mac address='52:54:00:f6:ff:9c'/>
<ip address='192.168.122.1' netmask='255.255.255.0'>

(το MAC address θα διαφέρει στον δικό σας υπολογιστή) βάζουμε αυτή τη γραμμή:

<domain name='local.kvm' localOnly="yes"/>

Πρέπει να έχουμε, δηλαδή, αυτές τις τρεις γραμμές:

<mac address='52:54:00:f6:ff:9c'/>
<domain name='local.kvm' localOnly="yes"/>
<ip address='192.168.122.1' netmask='255.255.255.0'>

Αποθηκεύουμε τις αλλαγές στο XML, εγκαταλείπουμε τον editor και το virsh λέει: Network default XML configuration edited. Αν όμως σκεφτούμε να ελέγξουμε για την αλλαγή, γράφοντας virsh net-dumpxml default, δεν θα τη δούμε:

[cvar AT dalvík] ~> virsh net-dumpxml default
[...]
  <mac address='52:54:00:f6:ff:9c'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
[...]

Δεν έχει ληφθεί ακόμη υπόψη και χρειάζεται να επανεκκινήσουμε το δίκτυο default: το σταματάμε πληκτρολογώντας virsh net-destroy default (ναι, σ’ αυτή την περίπτωση το “destroy” σημαίνει “stop”), κι αμέσως μετά το ξεκινάμε και πάλι με ένα virsh net-start default. Δείτε τώρα τι ισχύει:

[cvar AT dalvík] ~> virsh net-dumpxml default
[...]
  <mac address='52:54:00:f6:ff:9c'/>
  <domain name='local.kvm' localOnly="yes"/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
[...]

Ας κάνουμε κι έναν έλεγχο μ’ ένα VM “κάτω” από το local.kvm. Πριν από λίγο μεταφέραμε τη μηχανή qleap από το δίκτυο default στο δίκτυο delta. Εργαζόμενοι με παρόμοιο τρόπο τη μεταφέρουμε πίσω στο default — και φυσικά την ενεργοποιούμε γράφοντας virsh start qleap. Σε ελάχιστα δευτερόλεπτα θα υπάρχει ένα νέο DHCP lease για το qleap:

[cvar AT dalvík] ~> virsh net-dhcp-leases default
Expiry Time         MAC address       [...] IP address        Hostname [...]
----------------------------------------------------------------------------
2017-10-29 23:42:30 52:54:00:45:67:31 [...] 192.168.122.85/24 qleap    [...]

Συνδεόμαστε στη μηχανή (ssh userson@192.168.122.85) κι ελέγχουμε το FQDN του συστήματος:

userson@qleap:~> hostname -f
qleap.local.kvm

Όλα καλά, το FQDN του qleap είναι το αναμενόμενο.

Resolving από το host OS
Θα παρατηρήσατε ότι έως τώρα συνδεόμασταν από τον host στα VMs με βάση τα IP. Πράγματι, είναι απαραίτητο να γνωρίζουμε τις αριθμητικές διευθύνσεις: τα hostnames ή τα FQDNs που έχουν οι μηχανές ενός εικονικού δικτύου δεν είναι ορατά στο host computer, αφού αυτό δεν έχει πρόσβαση στους name servers των αντίστοιχων τοπικών δικτύων.

Προκειμένου να μην πληκτρολογούμε IPs θα μπορούσαμε να βάζαμε στο /etc/hosts του host κατάλληλα entries, ώστε αντί για IPs να θυμόμαστε hostnames ή FQDNs. Μάλιστα τις πληροφορίες του /etc/hosts λαμβάνουν υπόψη και τα dnsmasq instances για όλα τα εικονικά τοπικά δίκτυα, οπότε μια μηχανή, π.χ., από το default, είναι δυνατόν να φτάνει σε μια μηχανή του delta με βάση το hostname ή το FQDN της. Αλλά η χειροκίνητη ενημέρωση του /etc/hosts δεν είναι καθόλου βολική.

Μία σαφώς καλύτερη προσέγγιση είναι να φροντίσουμε ώστε οι επιθυμητοί name servers να υπάρχουν πάντα στο αρχείο /etc/resolv.conf του host. Σε ένα σύγχρονο laptop –ή ακόμη και σε ένα desktop computer– με Linux, τα θέματα της δικτύωσης τα διαχειρίζεται ο Network Manager. Η σχετική υπηρεσία μεταξύ άλλων δημιουργεί αυτόματα το /etc/resolv.conf. Έχουμε όμως τη δυνατότητα να υποδεικνύουμε τα domains ή/και τους name servers που θέλουμε να συμπεριλαμβάνονται στο resolv.conf, ανεξαρτήτως του δικτύου που τη δεδομένη στιγμή βρίσκεται ο υπολογιστής μας.

Στο laptop των δοκιμών μας, το οποίο όπως αναφέραμε τρέχει openSUSE Leap 42.3, υπάρχει φυσικά ο Network Manager. Θέλαμε να έχουμε πάντοτε τον name server του δικτύου delta στο /etc/resolv.conf του συστήματος, οπότε κάναμε μια μικρή επέμβαση στο αρχείο /etc/dhclient.conf. Συγκεκριμένα, φροντίσαμε ώστε να περιλαμβάνει τις ακόλουθες δύο γραμμές:

supersede domain-name "delta.is colder.xyz";
prepend domain-name-servers 10.20.30.254;

Η πρώτη σημαίνει ότι το resolv.conf θα έχει πάντα πάνω-πάνω την ακόλουθη οδηγία:

search delta.is colder.xyz

Έτσι, όταν πληκτρολογούμε μόνο το hostname ενός μηχανήματος, π.χ., randomhost, τότε πρώτα θα αναζητείται το IP του randomhost.delta.is και, αν δεν υπάρχει, μετά θα αναζητείται το IP του randomhost.colder.xyz. Το delta.is είναι το domain ενός από τα εικονικά τοπικά μας δίκτυα, ενώ το colder.xyz είναι ένα άλλο (δημόσιο) domain που έχουμε στη διάθεσή μας. Η δεύτερη γραμμή στο dhclient.conf σημαίνει ότι ανεξαρτήτως των name servers που θα πάρει ο Network Manager από τον DHCP server του εκάστοτε δικτύου, εντός του οποίου βρίσκεται το laptop, ο πρώτος name server που θα συμβουλεύεται το σύστημα θα είναι πάντοτε o 10.20.30.254: αυτό ακριβώς είναι το IP που έχει ο router και name server του εικονικού τοπικού δικτύου με όνομα delta. Προκειμένου ο Network Manager να λάβει αμέσως υπόψη τις νέες οδηγίες στο /etc/dhclient.conf, κι επομένως να δημιουργήσει μια ανανεωμένη εκδοχή του /etc/resolv.conf, αρκεί να το επανεκκινήσουμε:

[cvar AT dalvík] ~> sudo systemctl restart NetworkManager

Ιδού πώς μοιάζει το /etc/resolv.conf του laptop μας, όταν είναι συνδεδεμένο σε ένα ασύρματο δίκτυο κάπου στο Λευκαντί Ευβοίας:

[cvar AT dalvík] ~> cat /etc/resolv.conf
# Generated by NetworkManager
search delta.is colder.xyz
nameserver 10.20.30.254
nameserver 192.168.1.1

Ο πρώτος name server είναι εκείνος του δικτύου delta. Ο δεύτερος είναι εκείνος του modem/router με WiFi access point, σε μια καφετέρια κάπου στο Λευκαντί. Δείτε και το resolv.conf όταν το laptop είναι συνδεδεμένο στο οικιακό μας δίκτυο:

[cvar AT dalvík] ~> cat /etc/resolv.conf
# Generated by NetworkManager
search delta.is colder.xyz
nameserver 10.20.30.254
nameserver 192.168.178.2

Το μόνο που αλλάζει τώρα είναι η διεύθυνση IP του δεύτερου name server — και οι προσεκτικοί αναγνώστες αμέσως θα καταλάβουν ότι πρόκειται για τη διεύθυνση του Raspberry Pi μας, το οποίο παρέχει υπηρεσίες network-wide ad-blocker. Όπου κι αν βρισκόμαστε με το laptop μας, χάρη στις αλλαγές που κάναμε στο /etc/dhclient.conf μπορούμε να αναφερόμαστε σε VMs του delta είτε με βάση το hostname τους είτε με βάση το FQDN τους. Παράδειγμα:

[cvar AT dalvík] ~> ping -c 3 fedora26
PING fedora26.delta.is (10.20.30.200) 56(84) bytes of data.
64 bytes from fedora26.delta.is (10.20.30.200): icmp_seq=1 ttl=64 [...]
64 bytes from fedora26.delta.is (10.20.30.200): icmp_seq=2 ttl=64 [...]
64 bytes from fedora26.delta.is (10.20.30.200): icmp_seq=3 ttl=64 [...]

--- fedora26.delta.is ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1998ms
rtt min/avg/max/mdev = 0.141/0.155/0.164/0.010 ms

Μια χαρά.

Τροποποίηση συμπεριφοράς dnsmasq instance
Είναι πιθανό να επιθυμούμε την αλλαγή της συμπεριφοράς του dnsmasq instance για ένα συγκεκριμένο εικονικό τοπικό δίκτυο. Ας υποθέσουμε, για παράδειγμα, ότι το fedora26.delta.is θέλουμε να παίρνει πάντοτε το ίδιο IP, συγκεκριμένα το 10.20.30.5. Χρειαζόμαστε το MAC address της κάρτας Ethernet του VM, κι ένας τρόπος για να το μάθουμε είναι παρατηρώντας την έξοδο του virsh net-dhcp-leases delta (στο πλαίσιο της παρουσίασης μας, το ζητούμενο MAC address είναι το 52:54:00:ad:7e:49). Στη συνέχεια πληκτρολογούμε:

[cvar AT dalvík] ~> virsh net-update delta add ip-dhcp-host \
> "<host mac='52:54:00:ad:7e:49' ip='10.20.30.5' />" --live --config

Το virsh επιστρέφει το μήνυμα Updated network delta persistent config and live state, που σημαίνει ότι η αλλαγή ελήφθη υπόψη και δεν χρειάζεται επανεκκίνηση του δικτύου delta. Επανεκκινούμε μόνο τη μηχανή (virsh reboot fedora26), συνδεόμαστε μέσω SSH (ssh root@fedora26.delta.is) κι αμέσως ελέγχουμε τη διεύθυνση IP που έχει το ένα και μοναδικό Ethernet interface, το ens3:

[root@fedora26 ~]# ip a show ens3
2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel [...]
    link/ether 52:54:00:ad:7e:49 brd ff:ff:ff:ff:ff:ff
    inet 10.20.30.5/24 brd 10.20.30.255 scope global dynamic ens3
       valid_lft 3118sec preferred_lft 3118sec
    inet6 fe80::5054:ff:fead:7e49/64 scope link
       valid_lft forever preferred_lft forever

Τέλεια όλα.

Κανόνες port forwarding στο host computer
Το παράδειγμα που μόλις δώσαμε, με το static IP mapping, δεν ήταν εντελώς τυχαίο. Κάποιες φορές θα θέλουμε ένα VM, το οποίο βρίσκεται εντός ενός εικονικού τοπικού δικτύου, να είναι προσβάσιμο κι από μηχανήματα που είναι εξωτερικά ως προς το host computer (εν προκειμένω, το laptop με το openSUSE). Σε τέτοιες περιπτώσεις βοηθά το VM να έχει στατική IP. Φροντίσαμε πριν λίγο ώστε η εικονική μηχανή fedora26, του δικτύου delta, να παίρνει πάντοτε το ίδιο IP (το 10.20.30.5). Μετά την εγκατάσταση του Fedora 26 Server, εξάλλου, είναι ενεργοποιημένη μία υπηρεσία για τη διαχείριση (ή καλύτερα για την εποπτεία) του συστήματος μέσω web. Πράγματι, αν από έναν browser του host computer επισκεφτούμε τη διεύθυνση https://10.20.30.5:9090, θα μας ζητηθεί να συνδεθούμε σε έναν υπάρχοντα λογαριασμό χρήστη του συστήματος. Ως ένα απλό παράδειγμα εισαγωγής κανόνων port forwarding για ένα QEMU/KVM VM πίσω από ένα εικονικό τοπικό δίκτυο, ας δούμε πώς είναι δυνατόν να φτάσουμε στην ίδια σελίδα από ένα άλλο laptop, με macOS. Για το τοπικό δίκτυο που ορίζει το WiFi access point που τώρα είμαστε συνδεδεμένοι, το πλήρες όνομα του laptop με το openSUSE είναι dalvik.lan (το πλήρες όνομα του laptop με το macOS είναι mbpr15.lan, όμως αυτό δεν έχει καμία σημασία). Από έναν web browser του laptop με το macOS, όποτε πηγαίνουμε στο https://dalvik.lan:59090 θα πρέπει να ανακατευθυνόμαστε στο https://10.20.30.5:9090. Στην περίπτωσή μας, το port του host computer (dalvik.lan), που επιλέξαμε να είναι το 59090, θα μπορούσε να ταυτίζεται με το port του VM, που είναι το 9090. Σκόπιμα, όμως, αποφασίσαμε να τα διαφοροποιήσουμε.

Πριν κάνουμε κάτι, βεβαιωνόμαστε ότι το fedora26 είναι απενεργοποιημένο. Μετά, με δικαιώματα διαχειριστή φτιάχνουμε στον host το αρχείο qemu, κάτω από τον κατάλογο /etc/libvirt/hooks:

[cvar AT dalvík] ~> sudo touch /etc/libvirt/hooks/qemu

Ξανά με δικαιώματα διαχειριστή ανοίγουμε το qemu με τον text editor της προτίμησής μας. Γράφουμε εντός τον κώδικα BASH που ακολουθεί:

#!/bin/bash

IPT=/usr/sbin/iptables

if [ "${1}" = "fedora26" ]; then

  VM_IP=10.20.30.5
  VM_PORT=9090
  HOST_PORT=59090
  VIRT_NET=virbr1

  if [ "${2}" = "stopped" ] || [ "${2}" = "reconnect" ]; then
    $IPT -D FORWARD -o $VIRT_NET -d $VM_IP -j ACCEPT
    $IPT -t nat -D PREROUTING -p tcp --dport $HOST_PORT -j DNAT --to $VM_IP:$VM_PORT
  fi

  if [ "${2}" = "start" ] || [ "${2}" = "reconnect" ]; then
    $IPT -I FORWARD -o $VIRT_NET -d $VM_IP -j ACCEPT
    $IPT -t nat -I PREROUTING -p tcp --dport $HOST_PORT -j DNAT --to $VM_IP:$VM_PORT
  fi
fi

(Βασίζεται στο script από το επίσημο documentation του libvirt.) Για το δικό σας setup αλλάξτε τις μεταβλητές VM_IP, VM_PORT, HOST_PORT και VIRT_NET καταλλήλως, ενώ προσέξτε και τη μεταβλητή IPT. Αποθηκεύουμε, εγκαταλείπουμε τον editor και κάνουμε το αρχείο qemu εκτελέσιμο:

[cvar AT dalvík] ~> sudo chmod +x /etc/libvirt/hooks/qemu

Επανεκκινούμε το libvirt…

[cvar AT dalvík] ~> sudo systemctl restart libvirtd

…και βεβαίως ξεκινάμε το VM:

[cvar AT dalvík] ~> virsh start fedora26

Αυτό ήταν. Από το άλλο laptop (αυτό με το macOS) ανοίγουμε έναν web browser και κατευθυνόμαστε στο https://dalvik.lan:59090. Αν όλα έχουν πάει καλά, θα λάβουμε προειδοποίηση για self-signed πιστοποιητικό. Το αποδεχόμαστε και προχωράμε. Δείτε τα δύο screenshots που ακολουθούν, διαβάστε και τις αντίστοιχες περιγραφές. Επίσης: Καλή σας διασκέδαση!

Από τον web browser ενός laptop με macOS συνδεόμαστε στο laptop με το openSUSE, το οποίο έχει ρόλο virtualization host. Χάρη στους κανόνες port forwarding που ισχύουν για το libvirt, ανακατευθυνόμαστε στο web panel ενός VM που βρίσκεται εντός ενός εικονικού τοπικού δικτύου και γενικά δεν είναι προσβάσιμο από τον έξω κόσμο.

Από τον web browser ενός laptop με macOS συνδεόμαστε στο laptop με το openSUSE, το οποίο έχει ρόλο virtualization host. Χάρη στους κανόνες port forwarding που ισχύουν για το libvirt, ανακατευθυνόμαστε στο web panel ενός VM που βρίσκεται εντός ενός εικονικού τοπικού δικτύου και γενικά δεν είναι προσβάσιμο από τον έξω κόσμο.

Πρόσβαση στο web panel ενός εικονικού υπολογιστή με Fedora 26 Server, ο οποίος βρίσκεται εντός εικονικού τοπικού δικτύου και σε γενικές γραμμές δεν είναι προσβάσιμος από μηχανήματα ξένα ως προς τον virtualization host.

Πρόσβαση στο web panel ενός εικονικού υπολογιστή με Fedora 26 Server, ο οποίος βρίσκεται εντός εικονικού τοπικού δικτύου και σε γενικές γραμμές δεν είναι προσβάσιμος από μηχανήματα ξένα ως προς τον virtualization host.

Σας άρεσε το άρθρο; Αν ναι, τι θα λέγατε για ένα tip στο PayPal;

Leave a Reply

You must be logged in to post a comment.

Σύνδεση

Αρχείο δημοσιεύσεων