Software de virtualización
==========================
De las múltiples soluciones disponibles en *Linux* incluimos guía de unas pocas
de ellas, que en algunos casos serán meras notas, y en otros relaciones más extensas.
.. _software-virt-completa:
Virtualización completa
-----------------------
Al utilizar un *software* de virtualización para instalar y probar sistemas
operativos nos será muy útil conocer varios aspectos (además de los evidentes):
* Manipular el modo en que la máquina virtual se conecta a la red para poder
simular distintos escenarios. Por ejemplo, no es lo mismo que queramos
virtualizar un sistema de escritorio en que lo único que se necesita por lo
general es salida a internet que un servidor en que muy probablemente
necesitemos que el anfitrión pueda conectarse a él.
* Preservar estados de disco para recuperarlos cuando sea preciso (lo que se
conoce como :dfn:`instantáneas`).
* Crear discos que puedan utilizarse como plantilla para la creación de varias
máquinas virtuales. Por ejemplo, crear un único disco con una instalación
limpia de *Windows* 10, y usar éste como base para todos los discos de las
máquinas virtuales en que vayamos a virtualizar un *Windows* 10.
* Virtualizar tanto *firmware* |BIOS| como *firmware* |UEFI|.
* Tener mecanismos sencillos para poder transferir datos entre el anfitrión
y el huésped (p.e. un directorio compartido por ambos).
* Exportar máquinas virtuales a otros anfitriones o importarlas desde ellos.
Trataremos dos hipervisores: :program:`Virtualbox` porque ofrece la posibilidad
de ejecutarse en otros sistemas operativos como *Windows*, y |KVM| que es una
solución integrada oficialmente en el propio núcleo de *Linux*:
.. toctree::
:glob:
:maxdepth: 1
02.software/01.completa/[0-9]*
.. _software-contenedores:
Contenedores
------------
Los contenedores son una solución mucho más ligera\ [#]_ y eficiente con la
limitación de que tendrán que contener un sistema de idéntica naturaleza a la
del anfitrión, puesto que carecen de sistema operativo propio.
En los sistemas *Linux* este tipo de virtualización, muy esquemáticamente, se
basa en dos conceptos:
#. El **aislamiento** a través de:
* los :dfn:`espacios de nombres` (*namespaces*) del núcleo, que proporcionan
a los procesos una visión parcial de los procesos y recursos que gestiona
el sistema operativo. Todo aquello que no haya sido incluido en el mismo
espacio de nombres, no es accesible ni aparentemente existe. Para entender
este conceptos resulta indispensable la lectura del artículo `Digging into
Linux namespaces`_ (y `su segunda parte`_)\ [#]_.
* el :dfn:`enjaulamiento` (:manpage:`chroot`, :manpage:`pivot_root`) dentro de
un árbol de directorios, que logra su aislamiento del resto del sistema de
archivos.
#. La **limitación** de recursos a través de los :dfn:`grupos de control`
(abreviado *cgroups*). Gracias a ellos, por ejemplo, podremos impedir que un
proceso ocupe más de 128MiB de memoria |RAM|, aunque la máquina disponga de
mucha más. Para profundizar en ellos es conveniente el artículo `Cgroups
Introduction
`_. Tenga
presente que la versión predeterminada en *Debian* a partir de *Bulleye* es
la v2, así que es ésta versión la que se tomará como referencia.
En consecuencia, la creación de un contenedor supone:
* Crearle un conjunto de espacios de nombres propios (uno para su red, otro para
sus procesos, etc). De esta manera, dentro del contenedor sólo se tiene acceso
a aquello que el sistema operativo del anfitrión gestiona para el propio
contenedor.
* Enjaularlo dentro la porción del árbol de directorios que constituya su
\"sistema de archivos\".
* Crearle los grupos de control propios para limitar su uso de recursos.
Es relativamente frecuente utilizar el término |VM| para referir la máquina
virtual de la virtualización completa y |VE| (entorno virtual) para referir al
contenedor. Antes de comenzar, no obstante, es preciso saber que existen
distintos tipos de contenedores:
Según los **permisos** de sus usuarios
Hay dos tipos distintos:
.. _contenedor-privilegiado:
:dfn:`Contenedor privilegiado` (*privileged container*)
es aquel en que no se hace uso del concepto de *espacio de nombres de
usuario* y, en consecuencia, los usuarios y grupos del contenedor se
corresponden con los usuarios y grupos del anfitrión. Dicho de otro modo, la
acción que realice el usuario *root* en el contenedor es una acción que el
sistema operativo del anfitrión considera que está ejecutando su propio
*root*.
.. _contenedor-no-privilegiado:
:dfn:`Contenedor no privilegiado` (*unprivileged container*)
es aquel que hace uso de tal concepto, por lo que se mapean identificadores
de usuarios y grupos; y, en consecuencia, el administrador del contenedor
(|UID| **0** en el contenedor) no se corresponde con el administrador del
anfitrión (|UID| **0** en el anfitrión). Esto evita la posibilidad de que el
administrador escape del confinamiento del contenedor con permisos de
administrador.
.. note:: Todos estos conceptos se entienden muy bien si se leen con
detenimiento las explicaciones ya recomendadas del artículo `Digging into
Linux namespaces`_ y, en especial, `su segunda parte`_ en que se desarrolla
el concepto de espacio de nombres de usuario (*user namespace*). Más
adelante, además, se expone :ref:`un pequeño ejemplo de espacio de nombres de
usuario `.
Según los **procesos** que encierre
De nuevo, son dos los tipos:
.. _contenedor-sistema:
:dfn:`contenedor de sistema`
Es aquel diseñado para ejecutar aisladamente múltiples procesos a la
manera en que lo hace un sistema completo por lo que, en consecuencia,
ejecutará como primer proceso un programa :program:`init` (como
:ref:`systemd `). Es, por tanto, una solución más cercana al de
una virtualización completa, ya que dispondremos de un espacio de usuario
completo que recrea fielmente una distribución de *Linux*. |LXC| provee
contenedores de este tipo.
.. _contenedor-aplicacion:
:dfn:`contenedor de aplicaciones`
Es aquel diseñado para ejecutar aisladamente una única aplicación (por lo
general, un servicio), por lo que ejecutará como primer proceso tal
aplicación y no un programa :program:`init`. Estos contenedores, por
tanto, no ofrecen un sistema completo que gestionar. :program:`Docker`
provee contenedores de este tipo.
.. https://www.schutzwerk.com/en/blog/linux-container-intro/
Trataremos ambos tipos de contenedores:
.. toctree::
:glob:
:maxdepth: 1
02.software/03.contenedores/[0-9]*
.. rubric:: Notas al pie
.. [#] De hecho, este tipo de virtualización también recibe el nombre de
*virtulización ligera*.
.. [#] Esto incluye también a usuarios y grupos, de manera que un usuario que
dentro del contenedor actuara como usuario privilegiado (o sea, con el |UID|
0) fuera de él podría no serlo en absoluto. El interesantísimo artículo
mencionado ilustra `cómo crear a mano un entorno absolutamente aislado
`_
que nos puede ayudar a entender cómo funciona la *magia* de los contenedores.
Si a ese procedimiento se le añade limitación con *cgroups* (véase `Docker
Resource Management in Detail
`_), obtendremos
un contenedor *artesanal* sin necesidad de haber utilizado *software*
específico como |LXC| o *Docker*.
.. |BIOS| replace:: :abbr:`BIOS (Basic I/O System)`
.. |UEFI| replace:: :abbr:`UEFI (Unified Extensible Firmware Interface)`
.. |KVM| replace:: :abbr:`KVM (Kernel-based Virtual Machine)`
.. |LXC| replace:: :abbr:`LXC (LinuX Containers)`
.. |RAM| replace:: :abbr:`RAM (Random Access Memory)`
.. |UID| replace:: :abbr:`UID (User IDentifier)`
.. |GID| replace:: :abbr:`GID (Group IDentifier)`
.. |VM| replace:: :abbr:`VM (Virtual Machine)`
.. |VE| replace:: :abbr:`VE (Virtual Environment)`
.. _Digging into Linux namespaces: https://blog.quarkslab.com/digging-into-linux-namespaces-part-1.html
.. _su segunda parte: https://blog.quarkslab.com/digging-into-linux-namespaces-part-2.html