Índice de contenidos
1. Entorno
Este tutorial está escrito usando el siguiente entorno:
- Hardware: Slimbook Pro 2 13.3″ (Intel Core i7, 32GB RAM)
- Sistema Operativo: LUbuntu 18.04
- LXD 3.1
- LXC 3.1
2. Introducción
Este es un tutorial muy especial para mí dado que hace el número 100, así que me vais a permitir que sea un poco más apasionado y menos imparcial de lo habitual, aunque ninguna mentira voy a contar ;-).
En este tutorial vengo a hablar de una tecnología que me lleva enamorado desde hace ya unos cuantos meses, LXD.
En resumidas cuentas, con LXD te olvidas de tener que hacer máquinas virtuales con Virtualbox o VMWare, simplemente se crean como contenedores de sistemas ligeros al estilo Docker y se comportan como una máquina virtual, es la tecnología perfecta para simular una nube de AWS, o cualquier otro proveedor, en nuestro equipo de desarrollo. Además permite instalar Docker y Docker Compose para ejecutar contenedores dentro de las máquinas creadas.
Es una tecnología que está impulsada por Canonical y actualmente sólo funciona al 100% en Ubuntu y sus distintos sabores, como LUbuntu que es el que uso en el día a día. Esto puede ser una mala noticia para algunos y para otros el empujón definitivo para el uso de Ubuntu como su sistema operativo que, por otro lado, es el único al que tod@s podemos acceder de forma 100% gratuita.
Las posibilidades son infinitas con esta tecnología ya que nos permite crear n mil contenedores de sistema que en la práctica van a funcionar como máquinas virtuales pero sin las limitaciones de espacio y memoria que una tecnología de virtualización como Virtualbox o VMWare establecen. De este modo tú como desarrollador puedes tener un completo sistema de integración continua con todos los servicios (GitLab, Nexus, Jenkins, Sonarqube, …) cada uno instalado de forma independiente en su propia máquina para evitar conflictos y, por defecto, todos interconectados. También lo puedes usar para probar la última herramienta que haya salido o montar un servidor de pruebas. Este sería un ejemplo del listado de máquinas que tengo definidas actualmente en mi equipo a las que puedo acceder vía ssh como si fueran máquinas en la nube.
Por tanto si quieres aprovechar esta maravillosa tecnología y seguir los pasos de este tutorial, vas a necesitar al menos una máquina virtual con Ubuntu, aunque si no estás desarrollando nada específico para Mac, estás tardando en pasarte a lo bueno, la combinación Slimbook PRO + LUbuntu a mi me resulta perfecta para el desarrollo fullstack! :-).
Pero como el movimiento se demuestra andando…
3. Vamos al lío
Permíteme que insista… todo lo que vamos a ver a continuación aplica sólo en el sistema operativo Ubuntu, en concreto yo estoy utilizando LUbuntu 18.04.
La instalación de esta tecnología no puede ser más sencilla, se hace a través de un paquete snap ejecutando:
$> sudo snap install lxd --classic
Nota: si no lo tienes instalado simplemente ejecuta: sudo apt install snapd. También sólo en caso de estar en la versión 16.04 tenemos que ejecutar: sudo apt install zfsutils-linux -y para instalar este tipo de almacenamiento, en la versión 18.04 ya viene por defecto instalado.
Ahora para no tener que estar anteponiendo sudo al resto de comandos vamos a añadir a nuestro usuario actual al grupo «lxd» ejecutando estos comandos:
$> sudo usermod -a -G lxd ${USER} $> newgrp lxd
Ahora vamos a inicializar LXD para permitir la creación de los contenedores de sistema LXC que ya hemos dicho que se pueden tratar como máquinas virtuales al uso compatibles con Docker, que serían contenedores de aplicación. Simplemente ejecutamos:
$> lxd init
Al ejecutar este comando el sistema nos va a solicitar la siguiente información:
- Would you like to use LXD clustering? (yes/no) [default=no]: le decimos que no queremos usar el clustering.
- Do you want to configure a new storage pool? (yes/no) [default=yes]: le decimos que si queremos configurar un nuevo almacenamiento, será necesario para el filesystem de los contenedores que creemos.
- Name of the new storage pool [default=default]: le damos un nombre, default está bien.
- Name of the storage backend to use (btrfs, ceph, dir, lvm, zfs) [default=zfs]: vamos a utilizar el antes mencionado zfs, si no te sale esta opción por defecto, haz Control + C e instala el paquete zfsutils-linux y vuelve a empezar con el comando init.
- Create a new ZFS pool? (yes/no) [default=yes]: Confirmamos que sí queremos crear este pool.
- Would you like to use an existing block device? (yes/no) [default=no]: No queremos utilizar un bloque existente.
- Size in GB of the new loop device (1GB minimum) [default=15GB]: aquí configuramos el tamaño del almacenamiento inicial, esto va a depender del espacio de tu máquina y el número de contenedores que quieras levantar y el contenido que va a almacenar, pero yo recomiendo tirar por lo alto, en la medida de lo posible.
- Would you like to connect to a MAAS server? (yes/no) [default=no]: No queremos conectar con un servidor de MAAS.
- Would you like to create a new local network bridge? (yes/no) [default=yes]: Si queremos crear un «bridge» ya que será necesario para intercomunicar automáticamente los contenedores entre sí.
- What should the new bridge be called? [default=lxdbr0]: Dejamos ese nombre por defecto.
- What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: Lo dejamos en «auto» para no preocuparnos por tema de redes.
- What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: Lo ponemos en «none» para evitar conflictos.
- Would you like LXD to be available over the network? (yes/no) [default=no]: Le decimos que no, por el momento no queremos que LXD esté disponible en la red, sólo en nuestro equipo.
- Would you like stale cached images to be updated automatically? (yes/no) [default=yes] Nos pregunta si queremos actualizaciones automáticas, vamos a decirle que sí.
- Would you like a YAML «lxd init» preseed to be printed? (yes/no) [default=no]: Ahora mismo no nos interesa que nos saque la información en YAML.
Realizada la configuración inicial, ahora vamos a crear un contenedor de sistema base con la configuración necesaria para no tener que utilizar root y tener acceso remoto a través de SSH. Seguimos los siguientes pasos:
Creamos un nuevo contenedor partiendo de una imagen de Ubuntu 16.04 Server.
$> lxc launch ubuntu:16.04 prime
Una vez creado, como es la primera vez tardará un poco en descargar la imagen, vamos a listar todos los contenedores con el comando:
$> lxc list
Podemos ver que el contenedor está corriendo y ya tiene una IP asignada. Ahora para acceder dentro como root, vamos a ejecutar:
$> lxc exec prime bash
De esta forma el resto de los pasos los vamos a ejecutar dentro de nuestro contenedor «prime» como root. Lo primero que vamos a hacer es configurar la fecha y hora del sistema.
$(prime)> timedatectl set-timezone Europe/Madrid
Creamos un usuario no-root, por ejemplo, master:
$(prime)> useradd -m master
Establecemos una password para ese usuario:
$(prime)> sh -c 'echo master:superpass | chpasswd'
Añadimos el usuario a los grupos lxd y sudo:
$(prime)> usermod -a -G lxd,sudo master
Permitimos que el usuario tenga shell:
$(prime)> usermod -s /bin/bash master
Permitimos la autenticación en el contenedor:
$(prime)> sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config
Reiniciamos el servicio ssh:
$(prime)> service ssh restart
Editamos las variables del entorno del usuario “master”, editando el fichero /home/master/.bashrc
export LC_CTYPE=en_US.UTF-8 export LC_ALL=en_US.UTF-8
Leemos las nuevas variables:
$(prime)> source ~/.bashrc
Salimos del contenedor:
$(prime)> exit
Podemos probar que efectivamente podemos acceder al contenedor a través de SSH con el usuario el master y la password proporcionada:
$> ssh master@ip_asignada
Nuestro contenedor base ya está listo para poder ser reutilizado. Para ello vamos a publicarlo como imagen, para lo que tenemos que ejecutar los siguientes comandos:
$> lxc stop prime $> lxc publish prime --alias=prime
Ahora vamos a probar la integración con Docker, para ello creamos una nueva maquina con el comando a partir de la anterior con los modificadores de seguridad que nos permiten la creación de contenedores de Docker:
$> lxc launch prime docker-test -c security.nesting=true -c security.privileged=true
Ahora si ejecutamos:
$> lxc list
Podemos ver la IP que LXD le ha asignado de forma automática. Con lo que podemos acceder con el usuario «master» ejecutando:
$> ssh master@ip_docker_test
Ya estamos dentro de una máquina Ubuntu 16.04 vacía para nuestro uso y disfrute como si de una instancia EC2 de AWS se tratará pero más barato. Para el fin de probar la integración con Docker tenemos que instalar Docker-CE, para ello ejecutamos:
$(docker-test)> sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common $(docker-test)> curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - $(docker-test)> sudo add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" $(docker-test)> sudo apt-get update && sudo apt-get install -y docker-ce=17.06.0~ce-0~ubuntu $(docker-test)> sudo usermod -aG docker $USER $(docker-test)> docker --version
Y la podemos dejar ya preparada para la ejecucion de Docker Compose:
$(docker-test)> sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose $(docker-test)> sudo chmod +x /usr/local/bin/docker-compose $(docker-test)> docker-compose -version
Ahora para ver que efectivamente Docker está funcionado dentro del contenedor de sistema vamos a ejecutar el típico hello-world:
$(docker-test)> sudo docker run hello-world
Y para probar un servicio vamos a ejecutar una instancia de nginx de esta forma:
$(docker-test)> sudo docker run -d -p 82:80 nginx
Ahora si abrimos un navegador en nuestro equipo y accedemos a la URL: http://ip_docker_test:82 tenemos que ver la página por defecto del servidor de nginx funcionando.
4. Conclusiones
Esta es sólo la punta del iceberg de todo lo que nos permite hacer esta maravillosa tecnología. Entre otras cosas podemos asignar cuotas de disco y memoria a cada contenedor, hacer snapshots para volver a puntos estables en cualquier momento, manejar completamente las interfaces de red de cada contenedor, …
Abrazar Ubuntu tiene muchas y buenas ventajas. Ánimo que no duele 😉
Cualquier duda o sugerencia en la zona de comentarios.
Saludos.
Muy interesante Ruben
Mi primer GNU/Linux fue Mandrake Linux Power Pack 8. Ya casi 20 años de aquello . De hecho como un modo de aportar compre la caja con los 7 CD, los manuales y unos stickers, Los que aun conservo. Soy un usuario y he seguido fiel a Mandrake linux, Madriva y hoy Mageia 7.1 el último que estaba ocupando.
Hoy le he instalado Kubuntu 18.04 a mi notebook y decidi innovar 🙂 , esta tecnología es la que me llamaba la atención desde hace varios años y tu articulo me animo a lanzarme. Gracias Ruben!!!