Add network bridge guide to the cookbook.

Change-Id: If478196985aac7947067329957516f82bcb95ca4
This commit is contained in:
Maxim Cournoyer 2021-06-09 16:25:05 -04:00
parent b69bdcf77f
commit f24b14767d
No known key found for this signature in database
GPG key ID: 1260E46482E63562

View file

@ -77,6 +77,7 @@ manual}).
* Packaging:: Packaging tutorials
* System Configuration:: Customizing the GNU System
* Containers:: Isolated environments and nested systems
* Virtual Machines:: Virtual machines usage and configuration
* Advanced package management:: Power to the users!
* Software Development:: Environments, continuous integration, etc.
* Environment management:: Control environment
@ -155,6 +156,11 @@ Guix System Containers
* A Database Container::
* Container Networking::
Virtual Machines
* Network bridge for QEMU::
* Routed network for libvirt::
Advanced package management
* Guix Profiles in Practice:: Strategies for multiple profiles and manifests.
@ -3702,6 +3708,236 @@ sudo ip netns del $ns
sudo ip link del $host
@end example
@c *********************************************************************
@node Virtual Machines
@chapter Virtual Machines
Guix can produce disk images (@pxref{Invoking guix system,,, guix, GNU
Guix Reference Manual}) that can be used with virtual machines solutions
such as virt-manager, GNOME Boxes or the more bare QEMU, among others.
This chapter aims to provide hands-on, practical examples that relates
to the usage and configuration of virtual machines on a Guix System.
@menu
* Network bridge for QEMU::
* Routed network for libvirt::
@end menu
@node Network bridge for QEMU
@section Network bridge for QEMU
@cindex Network bridge interface
@cindex networking, bridge
@cindex qemu, network bridge
By default, QEMU uses a so-called ``user mode'' host network back-end,
which is convenient as it does not require any configuration.
Unfortunately, it is also quite limited. In this mode, the guest
@abbr{VM, virtual machine} can access the network the same way the host
would, but it cannot be reached from the host. Additionally, since the
QEMU user networking mode relies on ICMP, ICMP-based networking tools
such as @command{ping} do @emph{not} work in this mode. Thus, it is
often desirable to configure a network bridge, which enables the guest
to fully participate in the network. This is necessary, for example,
when the guest is to be used as a server.
@subsection Creating a network bridge interface
There are many ways to create a network bridge. The following command
shows how to use NetworkManager and its @command{nmcli} command line
interface (CLI) tool, which should already be available if your
operating system declaration is based on one of the desktop templates:
@example sh
# nmcli con add type bridge con-name br0 ifname br0
@end example
To have this bridge be part of your network, you must associate your
network bridge with the Ethernet interface used to connect with the
network. Assuming your interface is named @samp{enp2s0}, the following
command can be used to do so:
@example sh
# nmcli con add type bridge-slave ifname enp2s0 master br0
@end example
@quotation Important
Only Ethernet interfaces can be added to a bridge. For wireless
interfaces, consider the routed network approach detailed in
@xref{Routed network for libvirt}.
@end quotation
By default, the network bridge will allow your guests to obtain their IP
address via DHCP, if available on your local network. For simplicity,
this is what we will use here. To easily find the guests, they can be
configured to advertise their host names via mDNS.
@subsection Configuring the QEMU bridge helper script
QEMU comes with a helper program to conveniently make use of a network
bridge interface as an unprivileged user @pxref{Network options,,, QEMU,
QEMU Documentation}. The binary must be made setuid root for proper
operation; this can be achieved by adding it to the
@code{setuid-programs} field of your (host) @code{operating-system}
definition, as shown below:
@example lisp
(setuid-programs
(cons (file-append qemu "/libexec/qemu-bridge-helper")
%setuid-programs))
@end example
The file @file{/etc/qemu/bridge.conf} must also be made to allow the
bridge interface, as the default is to deny all. Add the following to
your list of services to do so:
@example lisp
(extra-special-file "/etc/qemu/host.conf" "allow br0\n")
@end example
@subsection Invoking QEMU with the right command line options
When invoking QEMU, the following options should be provided so that the
network bridge is used, after having selected a unique MAC address for
the guest.
@quotation Important
By default, a single MAC address is used for all guests, unless
provided. Failing to provided different MAC addresses to each virtual
machine making use of the bridge would cause networking issues.
@end quotation
@example sh
$ qemu-system-x86_64 [...] \
-device virtio-net-pci,netdev=user0,mac=XX:XX:XX:XX:XX:XX \
-netdev bridge,id=user0,br=br0 \
[...]
@end example
To generate MAC addresses that have the QEMU registered prefix, the
following snippet can be employed:
@example sh
mac_address="52:54:00:$(dd if=/dev/urandom bs=512 count=1 2>/dev/null \
| md5sum \
| sed -E 's/^(..)(..)(..).*$/\1:\2:\3/')"
echo $mac_address
@end example
@subsection Networking issues caused by Docker
If you use Docker on your machine, you may experience connectivity
issues when attempting to use a network bridge, which are caused by
Docker also relying on network bridges and configuring its own routing
rules. The solution is add the following @code{iptables} snippet to
your @code{operating-system} declaration:
@example lisp
(service iptables-service-type
(iptables-configuration
(ipv4-rules (plain-file "iptables.rules" "\
*filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A FORWARD -i br0 -o br0 -j ACCEPT
COMMIT
"))
@end example
@node Routed network for libvirt
@section Rounted network for libvirt
@cindex Virtual network bridge interface
@cindex networking, virtual bridge
@cindex libvirt, virtual network bridge
If the machine hosting your virtual machines is connected wirelessly to
the network, you won't be able to use a true network bridge as explained
in the preceding section (@pxref{Network bridge for QEMU}). In this
case, the next best option is to use a @emph{virtual} bridge with static
routing and to configure a libvirt-powered virtual machine to use it
(via the @command{virt-manager} GUI for example). This is similar to
the default mode of operation of QEMU/libvirt, except that instead of
using @abbr{NAT, Network Address Translation}, it relies on static
routes to join the @abbr{VM, virtual machine} IP address to the
@abbr{LAN, local area network}. This provides two-way connectivity to
and from the virtual machine, which is needed for exposing services
hosted on the virtual machine.
@subsection Creating a virtual network bridge
A virtual network bridge consists of a few components/configurations,
such as a @abbr{TUN, network tunnel} interface, DHCP server (dnsmasq)
and firewall rules (iptables). The @command{virsh} command, provided by
the @code{libvirt} package, makes it very easy to create a virtual
bridge. You first need to choose a network subnet for your virtual
bridge; if your home LAN is in the @samp{192.168.1.0/24} network, you
could opt to use e.g.@: @samp{192.168.2.0/24}. Define an XML file,
e.g.@: @file{/tmp/virbr0.xml}, containing the following:
@example
<network>
<name>virbr0</name>
<bridge name="virbr0" />
<forward mode="route"/>
<ip address="192.168.2.0" netmask="255.255.255.0">
<dhcp>
<range start="192.168.2.1" end="192.168.2.254"/>
</dhcp>
</ip>
</network>
@end example
Then create and configure the interface using the @command{virsh}
command, as root:
@example
virsh net-define /tmp/virbr0.xml
virsh net-autostart virbr0
virsh net-start virbr0
@end example
The @samp{virbr0} interface should now be visible e.g.@: via the
@samp{ip address} command. It will be automatically started every time
your libvirt virtual machine is started.
@subsection Configuring the static routes for your virtual bridge
If you configured your virtual machine to use your newly created
@samp{virbr0} virtual bridge interface, it should already receive an IP
via DHCP such as @samp{192.168.2.15} and be reachable from the server
hosting it, e.g.@: via @samp{ping 192.168.2.15}. There's one last
configuration needed so that the VM can reach the external network:
adding static routes to the network's router.
In this example, the LAN network is @samp{192.168.1.0/24} and the router
configuration web page may be accessible via e.g.@: the
@url{http://192.168.1.1} page. On a router running the
@url{https://librecmc.org/, libreCMC} firmware, you would navigate to
the @clicksequence{Network @click{} Static Routes} page
(@url{https://192.168.1.1/cgi-bin/luci/admin/network/routes}), and you
would add a new entry to the @samp{Static IPv4 Routes} with the
following information:
@table @samp
@item Interface
lan
@item Target
192.168.2.0
@item IPv4-Netmask
255.255.255.0
@item IPv4-Gateway
@var{server-ip}
@item Route type
unicast
@end table
where @var{server-ip} is the IP address of the machine hosting the VMs,
which should be static.
After saving/applying this new static route, external connectivity
should work from within your VM; you can e.g.@: run @samp{ping gnu.org}
to verify that it functions correctly.
@c *********************************************************************
@node Advanced package management