LXD, Virtualhosts y Docker - perfeccion-ar/infraestructura-clasica-y-avanzada GitHub Wiki

Proxy Reverso simple, con Apache 2 bajo LXD, apuntado a un Django

Relacionado:

Introducción

En la infraestructura del aula tendemos a meter todo en containers LXD.

Para poder mandar tráfico del puerto 80 del server a cada uno de los containers de los alumnos, usamos un Apache con Virtualhost. La elección de Apache sobre Nginx, es tan solo porque es más simple enseñar la sintaxis de Apache. Dejaremos Nginx para más adelante, junto con Docker.

Este Apache conviene que esté también en un container LXD. Podría estar afuera, en el mismo host. Pero no sería transportable ni estaría bien aislado.

Puesto que uno de los propósitos del taller es estimular en los alumnos la creación de sus propios servidores y VPS, y que ellos mismos algún día puedan hacer auto hosting o "MaaS" (metal-as-a-service), es que ofrezco estos apuntes de mano sobre cómo fue configurado.

Durante el desarrollo de las siguientes líneas, se crearán dos containers:

El primero es un "balancer" simple con Apache. Tiene configurado cada dominio de cada alumno en un achivo separado .conf, y adentro definido cada dominio que traiga el alumno en un VirtualHost aparte. Cada Virtualhost apunta mediante Proxy Reverse al container LXD del alumno.

El segundo es un container de ejemplo, que tendrá Django. Este container estará "escondido" en su propia red, y solo recibirá tráfico del "Balancer". Finalmente, el container con Django tiene un dominio registrado en nic.ar, llamado ecoplatonica.com.ar, con DNS gratuitos proporcionados por Cloudflare. Si no tiene un dominio, obtenga un subdominio gratuito en duckdns.org (ejemplo, catoto.duckdns.org) y apuntelo a este server, 37.27.49.225

El primer container cumple funciones de Proxy Reverso.

Pomposamente lo hemos llamado Balancer, aunque para que "balancee", propiamente dicho, entre varios containers con el mismo servicio (ejemplo, 10 djangos), necesitaría activar el módulo lbmethod_byrequests

En nuestro ejemplo, por ahora este [ balancer - proxy reverso], solo nos hará de dispatcher del puerto 80, reenviando un dominio que le configuraremos mediante Virtualhost, hacia un único container con Django.

Luego usted podrá agregar más virtualhosts que apunten hacia otros containers, con todos los servicios que se le antoje. Ejemplos:

  • sitio1.com con Java (ej: un Tomcat)
  • sitio2.com con Node (ej: Express)
  • pepe.sitio3.com con Ruby (ej: Sinatra, Rails)
  • cachita.duckdns.com con PHP (ej: un Wordpress bajo otro Apache, un Laravel bajo un Nginx)
  • etc, etc

Si quiere más detalles sobre este patrón de diseño, consulte la excelente distinción que hace entre Proxy Reverso, Balancer propiamente dicho, e incluso API Gateway que hace el arquitecto de software de ByteByteGo, en este corto video: https://www.youtube.com/watch?v=RqfaTIWc3LQ

Container 1: "Balancer con Proxy Reverso"

Ejemplo de creación de un container LXD para que haga de ProxyPassReverse

lxc launch ubuntu:22.04 balancer

Para más información sobre lxc launch, instalación de LXD y creación de containers, consulte el artículo sobre LXD

Ahora entramos al container

lxc shell balancer

Instalamos "solo" Apache. Para reducir la superficie de ataque, nada de agregar PHP ni lenguajes backend.

apt-get update && apt-get install apache2

Necesitamos activar algunos módulos

a2enmod headers
a2enmod ssl
a2enmod proxy
a2enmod proxy_http
a2enmod proxy_connect

Quitamos la configuración del sitio de bienvenida

cd /etc/apache2/sites-available/
a2dissite 000-default.conf
rm 000-default.conf
rm default-ssl.conf

Restarteamos Apache

systemctl restart apache2

Importante: este container "balancer" debe recibir todo el tráfico del puerto 80 y 443 del host. Se hace mediante una regla de proxy LXD. Ejemplo:

lxc config device add balancer balancerport80 proxy listen=tcp:0.0.0.0:80 connect=tcp:127.0.0.1:80

Para probar proxear hacia otro container, crearemos un proxy reverso hacia un servicio pequeño instalado en otro container. Por ejemplo, con Django

Para ello, salimos con exit, y en el host creamos otro container

Container 2: servicio con Django

En el host, donde hemos instalado LXD, creamos el segundo container,

lxc launch ubuntu:22.04 django-prueba

Entramos al container

lxc shell django-prueba

Instalamos Python adentro

apt-get update && apt install python3

Para liberarnos de la versión de Python por defecto que nos instala apt-get , y para no seguir instalando librerías que puedan comprometer el sistema operativo del container, instalaremos el resto de las librerías con un manejador de entornos de Python. Podemos usar Virtualnwrapper, o mi preferido, Miniconda.

La siguiente es una práctica sumamente aconsejada: Linux usa muchas librerías de Python para su funcionamiento interno. Si nos pusieramos a instalar las nuestras para nuestro proyecto, siempre como root o con sudo, podríamos estropear el sistema operativo.

Finalmente, las librerías de Python conviene administrarlas mediante pip en su propio espacio de usuario.

A continuación, como instalar Miniconda, Pip, y un Django de prueba.

Si no le salen los siguientes pasos, simplemente levante un miniserver http, con python3 -m http.server

Para instalar Miniconda:

wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh
~/miniconda3/bin/conda init
source ~/.bashrc
pip install virtualenvwrapper
conda update conda
conda update --all

Ahora creamos un pequeño entorno con Python 3.12, o con la versión que sea que aconseje la página de Releases de Django. A la fecha: Python 3.12 para Django 5. Esto es muy importante si venimos con un Django viejo: consulte este sitio para estar seguro: https://docs.djangoproject.com/en/5.0/faq/install/#what-python-version-can-i-use-with-django

Entonces, si nos hemos decidido en efecto, por Python 3.12:

conda create -n py3.12 Python=3.12

Activamos el entorno virtual:

conda activate py3.12

Ya tenemos nuestro Python 3.12 totalmente aparte del sistema operativo. Ahora generamos un proyecto pequeño en Django.

pip install django
django-admin startproject myproject
cd myproject
python manage.py migrate

Editamos myproject/settings.py y dejamos esta línea así

ALLOWED_HOSTS = ["*"]

Ahora arrancamos Django. Pero si no queremos que se cierre al cerrar la terminal, conviene dejarlo corriendo bajo algún multiplexador de terminal, como Byobu

python manage.py runserver 0.0.0.0:8000

Obtendremos

Django version 5.0.7, using settings 'myproject.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.

Dejamos Django corriendo en el container django-prueba.

En otra terminal, entramos al container balancer para chequear si el Apache podrá llegar hasta el container django-prueba. Pero primero, ¿cuál es la ip del container con Django?

  • Para saberlo desde adentro del container: ip ad
  • Para saberlo sin entrar al container, desde el host: lxc list
ianr@host:~$ lxc list
+------------------+---------+-----------------------+------+-----------+-----------+
|       NAME       |  STATE  |         IPV4          | IPV6 |   TYPE    | SNAPSHOTS |
+------------------+---------+-----------------------+------+-----------+-----------+
| balancer         | RUNNING | 10.149.127.90 (eth0)  |      | CONTAINER | 0         |
+------------------+---------+-----------------------+------+-----------+----
| django-prueba    | RUNNING | 10.149.127.200 (eth0) |      | CONTAINER | 0         |
+------------------+---------+-----------------------+------+-----------+-----------+

Entonces, desde el balancer, probamos con curl, o con algún navegador de consola, como GNU w3m

sudo apt-get install w3m

w3m http://10.149.127.200:8000

Respuesta:

View release notes for Django 5.0

The install worked successfully! Congratulations!

You are seeing this page because DEBUG=True is in your settings file and you have not configured any URLs.

Creación de Virtualhost con ProxyPassReverse

Seguimos en el container balanceador. Creamos un virtualhost, y adentro le definimos un dominio, y un ProxyReverse con un container LXD como destino. Aquí tiene como queda el archivo, situado en /etc/apache2/sites-available/ecoplatonica.com.ar.conf (debe terminar en .conf)

<VirtualHost *:80>
    ServerAdmin [email protected]
    ServerName ecoplatonica.com.ar

    ProxyPreserveHost On

    CustomLog /var/log/apache2/ecoplatonica.log combined
    ErrorLog /var/log/apache2/ecoplatonica-error.log

    <Proxy *>
            Order deny,allow
            Allow from all
    </Proxy>

    ProxyPreserveHost On
    ProxyPass / http://10.149.127.200:8000/
    ProxyPassReverse / http://10.149.127.200:8000/

</VirtualHost>

Activamos el virtualhost y reiniciamos Apache

a2ensite ecoplatonica.com.ar.conf
apachectl configtest
systemctl restart apache2

Si no tuviéramos delegado el dominio, igual podemos probar localmente con w3m. Editamos /etc/hosts y agregamos

127.0.0.1 ecoplatonica.com.ar

Listo. Ahora el container balancer creerá que "él" tiene el sitio instalado adentro. Si hacemos

w3m ecoplatonica.com.ar

Obtendremos nuevamente, como cuando hicimos w3m http://10.149.127.200:8000

django

View release notes for Django 5.0

The install worked successfully! Congratulations!

Docker

  • Se puede mandar tráfico a Docker?
  • Si, se puede, pero no conviene meter Docker y LXD en el mismo host. Se pelearán por aplicar reglas de iptables, y uno u otro pueden quedarse "ciegos" de red. Entonces, Docker debería correr dentro de una VM, o dentro de un Container en un pool con BTRFS. Consulte las opciones 2 y 3 de la sección "Docker adentro de LXD".

Video relacionado

Configuración en una VPS del alumno Oscar, alojado en Contabo, instalada LXD. Adentro, un container LXD contiene un Apache, que hace de ProxyReverse hacia otro container LXD que atiende en un puerto 3000, con un proyecto en Ruby on Rails. Se utiliza Cloudflare como DNS: - requiere solicitar invitación a [email protected] https://youtu.be/x8RyJ2q85T4

Clase mas o menos con el mismo del mismo tenor, de Sergio Alberto: https://youtu.be/Fp67WDSFyeg

Y eso es todo lo que sé sobre ProxyPassReverse 😄

Cualquier duda, consultas a [email protected]

⚠️ **GitHub.com Fallback** ⚠️