January 13, 2021

2800 words 14 mins read

Instalación automática de Shiny y RStudio server en Raspberry Pi con Ansible

Instalación automática de Shiny y RStudio server en Raspberry Pi con Ansible

Tengo una publicación relacionada sobre la instalación manual de Shiny y RStudio Server en una Raspberry Pi, pero incluso con los últimos avances en el soporte de software para la arquitectura ARM, este proceso aún consume mucho tiempo y requiere mucho copiar/pegar y observar la terminal esperando que se complete una tarea para poder comenzar con la siguiente, así que decidí idear una mejor solución, y es automatizar el proceso para que pueda dejarse desatendido y regresar más tarde cuando haya terminado.

Para automatizar el proceso de instalación y configuración, decidí usar Ansible, aquellos en DevOps deben estar familiarizados con el poder de Ansible, pero incluso si nunca has escuchado de ello, no te preocupes, no necesitas conocer Ansible para aprovechar sus capacidades de automatización, yo mismo no soy un experto en Ansible y he sido capaz de realizar este proyecto con solo conocimientos básicos de la herramienta, así que si yo puedo hacerlo, tú también puedes. Te guiaré a través del proceso asumiendo que no tienes experiencia previa con esta herramienta y solo algunas habilidades básicas de terminal de Linux.

Ansible es una herramienta de implementación de aplicaciones, administración de configuración y aprovisionamiento de software de código abierto que habilita la infraestructura como código. Se ejecuta en muchos sistemas de tipo Unix y puede configurar tanto sistemas tipo Unix como Microsoft Windows. En términos simples, te permite automatizar tareas en tu infraestructura (una, o muchas Raspberry Pi a la vez en nuestro caso) definiendo un conjunto de pasos para ejecutar en archivos YAML llamados “playbooks”. Me sacrifique por el equipo y escribí algunos playbooks de Ansible para automatizar la mayor parte del proceso de instalación, pero dejando algo de espacio para que configures la instalación a tu gusto a través de un archivo de configuración, por lo que no necesitas modificar los playbooks (lo que requerirá que sepas cómo funcionan). Aunque, si deseas tener una comprensión básica de cómo funciona esta herramienta, hay una buena serie de Ansible para principiantes en el canal de YouTube de Jeff Geerling y si eres el tipo de personas que prefiere leer en lugar de ver cosas, aquí hay un Tutorial de Ansible para principiantes bastante agradable pero lamentablemente, está sólo en inglés.

✏️ Ten en cuenta que esto solo se ha probado con las versiones de software especificadas en el archivo config_vars.yml, es muy probable que funcione aún con las versiones de software más nuevas, pero en algunos casos, podría requerir algunas modificaciones a los playbooks, las que haré tan pronto como note el problema.

Prepara la Raspberry Pi

Incluso si la mayor parte del proceso se puede automatizar con Ansible, aún necesitamos al menos una Raspberry Pi en funcionamiento para configurar, por lo tanto, debemos comenzar cargando un sistema operativo (SO) en una tarjeta SD (recomiendo al menos 32 GB clase 10 HC1). Ten en cuenta que RStudio Server es compatible solo con los sistemas operativos arm64, por lo que si deseas poder instalarlo, deberás elegir un sistema operativo de 64 bits, los playbooks funcionan tanto con Raspberry Pi OS como con Ubuntu.

Descarga “Raspberry Pi Imager” del sitio oficial e instálalo en tu sistema, ejecuta “Raspberry Pi Imager”, selecciona un sistema operativo adecuado, elije tu “Tarjeta SD” y presiona “Escribir”.

Una vez finalizado el proceso, tendras una instalación limpia de un sistema operativo en tu tarjeta micro SD, inserta la tarjeta en tu Raspberry Pi, conecta un teclado y una pantalla y enciéndela.

Inicia sesión en el sistema (el usuario y la contraseña predeterminados son pi y raspberry para Raspberry Pi OS, y en Ubuntu es ubuntu tanto para el usuario como para la contraseña) y ejecuta una actualización inicial del sistema con estos comandos:

sudo apt update
sudo apt dist-upgrade

A continuación, debes configurar una IP estática para que puedas encontrar tu Pi fácilmente en tu red más adelante.

Para configurar una IP estática en Raspberry Pi OS, ejecuta estos comandos. Esta es una configuración de IP de muestra para una conexión por cable, modificala de acuerdo a tus propias necesidades:

# Configuración IP de muestra:
sudo nmcli c mod 'Wired connection 1' ipv4.addresses 192.168.3.101/24 ipv4.method manual
sudo nmcli con mod 'Wired connection 1' ipv4.gateway 192.168.3.1
sudo nmcli con mod 'Wired connection 1' ipv4.dns "192.168.3.1"
sudo nmcli c down 'Wired connection 1' && sudo nmcli c up 'Wired connection 1'

Luego debes volver a establecer una nueva conexión SSH con tu Pi ya que el IP ha cambiado.

Y para configurar la IP en Ubuntu, debes crear este archivo, sudo nano /etc/netplan/01-netcfg.yaml, agregar el siguiente contenido (edita según sea necesario) y aplicar la configuración con sudo netplan apply.

network:
    version: 2
    renderer: networkd
    ethernets:
        eth0:
            dhcp4: false
            addresses:
                - 192.168.3.101/24
            nameservers:
                addresses: [8.8.8.8, 8.8.4.4, 192.168.3.1]
            routes:
                - to: default
                  via: 192.168.3.1

Luego necesitamos establecer algunas configuraciones básicas con raspi-config. Ejecuta sudo raspi-config y realiza las siguientes tareas (en Ubuntu debes instalarlo primero con sudo apt install raspi-config):

  • Opcionalmente, cambia la contraseña del usuario “pi” (System Options –> Password)
  • Habilita el servidor SSH (Interface Options –> SSH)
  • Establece tu configuración regional (Localization Options)
  • Expande el sistema de archivos para utilizar la capacidad total de tu tarjeta SD (Advanced Options –> Expand Filesystem)
  • Deshabilita los nombres de interfaz de red predecibles (Advanced Options –> Network Interface Names)

Cuando hayas terminado, sal de la herramienta raspi-config y reinicia tu Pi.

Si no tienes una, debes crear una clave SSH, incluso si es posible usar Ansible proporcionando una contraseña para tus hosts de forma interactiva, una forma más conveniente y segura de hacerlo es usando un par de claves SSH. Para crear una, ejecuta los siguientes comandos en la terminal:

# Crea la carpeta .ssh
cd ~
mkdir .ssh
cd .ssh
# Crea el archivo authorized_keys
touch authorized_keys

# Establece permisos de acceso adecuados
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

# Crea el par de claves
ssh-keygen
# Agregua la nueva clave al archivo authorized_keys
cat id_rsa.pub >> authorized_keys

# Si usas Putty como tu cliente SSH (Windows), genera una clave ppk; de lo contrario, ignora estos pasos
sudo apt install putty-tools
puttygen id_rsa -o id_rsa.ppk

Copia los archivos id_rsa e id_rsa.pub (id_rsa.ppk si corresponde) a la máquina que va a usar para ejecutar los playbooks, a mí me gusta usar sftp pero puedes hacerlo de la manera que prefieras (por ejemplo, con una memoria USB). Después de haber copiado los archivos de clave, elimínalos de tu Pi con rm ~/.ssh/id_rsa*. Si ya tienes una clave SSH, confío en que sabes cómo agregarla a tu sistema operativo en el momento de cargarlo con Raspberry Pi Imager.

Ahora tu Pi está lista, desconecta el teclado y el monitor, conecta la Raspberry Pi a tu red (recomiendo usar una conexión por cable).

Instala Ansible

En teoría, podrías instalar Ansible en la propia Raspberry Pi y ejecutar los playbooks directamente en ella con connection: local pero no sería práctico, es mejor ejecutar los playbooks desde una computadora que no sea tu Raspberry Pi.

Para instalar Ansible, si tienes un sistema basado en Unix (es decir, Linux, macOS) a tu disposición, tienes suerte, instalar Ansible es muy simple.

# Instala python3
sudo apt install python3 # En macOS usa `brew install python3`
# Instala pip3
sudo apt install python3-pip 
# Instala la versión 9.5.1 de Ansible con pip3 (Por reproducibilidad) 
sudo pip3 install ansible==9.5.1 --break-system-packages

Si estás en Windows, lamentablemente, no hay forma de ejecutar Ansible de forma nativa, tu mejor opción es habilitar WSL (Subsistema de Windows para Linux), instalar una distribución de Linux del Microsoft Store (recomiendo Ubuntu) y ejecutar los pasos anteriores en tu máquina virtual Linux.

Puedes encontrar una guía detallada para instalar WSL aquí y puede encontrar más información sobre la instalación de Ansible en el sitio de documentación oficial.

Además, dado que vamos a estar instalando varios paquetes desde la fuente en una SBC de baja potencia, algunas de estas tareas van a tomar bastante tiempo y la conexión SSH podría cerrarse automáticamente por inactividad, para evitar esta situación, activa el envío de paquetes “keep-alive” al servidor editando el archivo ssh_config con sudo nano /etc/ssh/ssh_config en la computadora que está ejecuntado Ansible y agregando estas dos líneas debajo de Host *:

    ServerAliveInterval 300
    ServerAliveCountMax 2

⚠️ Es muy importante no saltarse el paso anterior, de lo contrario, la conexión SSH podría fallar silenciosamente mientras se ejecutan tareas largas en Ansible y vas a estar esperando inútilmente con tu Raspberry Pi sin hacer nada en realidad.

Descarga y configura los Playbooks

Los playbooks están en un repositorio público en GitHub, puedes clonar el repositorio con estos comandos:

# Instala git si aún no lo tienes
sudo apt install git
# Clonar el último commit del repositorio
git clone https://github.com/andresrcs/raspberry_pi_server.git --depth 1

Ansible no ejecuta playbooks en “carpetas de escritura global”, por lo que debes configurar los permisos de la carpeta raspberry_pi_server en 755.

sudo chmod 755 raspberry_pi_server

Ten en cuenta que en WSL es necesario volver a montar la unidad C para poder cambiar los permisos de los archivos, por lo que debes hacer esto antes de cambiar los permisos:

sudo umount /mnt/c 
sudo mount -t drvfs C: /mnt/c -o metadata

Para configurar los playbooks, primero debes definir tu “inventario”, esta es una lista de los hosts a los que te vas a conectar, edita el archivo raspberry_pi_server/inventory.ini y agrega la IP de tu(s) Raspberry Pi(s):

[raspberries] # Esto representa un grupo de Raspberries
raspberry_01 ansible_host=192.168.3.101 # Este es el nombre de host y la IP de una Raspberry Pi individual
# Puedes agregar tantas Raspberries como necesites

Luego, configura las variables comunes para el grupo [raspberries] editando el archivo raspberry_pi_server/group_vars/raspberries.yml, lo más importante para verificar aquí es la ruta a tu clave ssh y el usuario predeterminado para el sistema operativo que estes usando.

---
ansible_user: pi # Este es el usuario predeterminado para el sistema operativo
ansible_become_method: sudo
ansible_python_interpreter: /usr/bin/python3
ansible_ssh_private_key_file: ~/.ssh/raspberrypi_key # La ubicación de la clave ssh en la computadora que está ejecuntando Ansible.

Ahora, puedes configurar las opciones de instalación editando las variables en el archivo raspberry_pi_server/vars/config_vars.yml, las opciones ya configuradas están bien para la mayoría de los casos de uso, incluidas configuraciones de seguridad razonables, pero como mínimo, debes configurar tu contraseña personal para el usuario principal de PostgreSQL. También puedes elegir tu método preferido para instalar R, si no deseas usar la opción predeterminada, ten en cuenta que usar la opción R4Pi solo es posible con Raspberry Pi OS y siempre instalará la última versión de R disponible.

---
# Configuraciones del sistema ##################################################

# Parametros Swap
swap_file_path: '/var/swap.1'
# Utiliza cualquiera de los siguientes sufijos
# c=1
# w=2
# b=512
# kB=1000
# K=1024
# MB=1000*1000
# M=1024*1024
# xM=M
# GB=1000*1000*1000
# G=1024*1024*1024
swap_file_size: '3GB'
swappiness: '10'

# Instalar Nginx?
install_nginx: true

# Instalar PostgreSQL?
install_postgresql: true

# Configuraciones de seguridad #################################################

# Puertos para abrir
exposed_ports:
  - { rule: 'allow', port: 22, proto: 'tcp' }     # ssh
  - { rule: 'allow', port: 22, proto: 'udp' }     # ssh
  - { rule: 'allow', port: 80, proto: 'tcp' }     # http
  - { rule: 'allow', port: 5432, proto: 'tcp' }   # Postgresql (omitir si Postgresql no está instalado)
  - { rule: 'allow', port: 5432, proto: 'udp' }   # Postgresql (omitir si Postgresql no está instalado)
  # - { rule: 'allow', port: 8787, proto: 'tcp' } # RStudio Server (descomentar si Nginx no está instalado)
  # - { rule: 'allow', port: 3838, proto: 'tcp' } # Shiny Server (descomentar si Nginx no está instalado)

# Contraseña para el usuario principal de PostgreSQL
postgres_password: 'very_secure_password'

# Reglas de acceso para PostgreSQL
postgresql_rules:
postgresql_rules:
  - { contype: local, users: postgres, address: samehost, method: trust }
  - { contype: local, users: all, address: samehost, method: trust }
  - { contype: hostssl, users: all, address: 0.0.0.0/0, method: scram-sha-256 }
  - { contype: host, users: all, address: 0.0.0.0/0, method: scram-sha-256 }
  - { contype: hostssl, users: all, address: '::0/0', method: scram-sha-256 }
  - { contype: host, users: all, address: '::0/0', method: scram-sha-256 }
  - { contype: host, users: all, address: 127.0.0.1/32, method: scram-sha-256 }
  - { contype: host, users: all, address: '::1/128', method: scram-sha-256 }

# Versiones principales de software ############################################

# Versión de R a instalar
use_r4pi: true # Si se establece en verdadero, se instalará la última versión de R, esto solo es compatible con
                # Raspberry Pi OS.
use_rig: false # Si se establece en verdadero, no olvide especificar una versión R en la siguiente línea
r_version: '' # (e.g. '4.3.3') Actualmente, solo puede elegir la versión R si va a ser
                   # instalado con rig o compilado (con 'use_r4pi' y 'use_rig' establecidos como false).

# Versión de shiny-server a instalar
shiny_server_version: 'v1.5.21.1012'

# Versión del servidor rstudio-server a instalar
rstudio_version: '2024.04.0-daily+651'

Ejecuta los Playbooks

En condiciones ideales, como usando el último modelo de Raspberry Pi, con 8 GB de RAM, booteando desde un SSD, y conectado a una red estable, puedes simplemente acceder a la carpeta raspberry_pi_server y ejecutar el libro de jugadas site.yml para instalar todo de una sóla vez:

cd raspberry_pi_server
ansible-playbook site.yml

Pero en condiciones menos que ideales, es muy probable que encuentres algunos errores aleatorios causados por la sobrecarga de la Pi o conexiones de red inestables, por lo que, para mitigar este problema y hacer que el proceso de instalación sea más flexible, he dividido el proceso en tres playbooks individuales:

cd raspberry_pi_server
ansible-playbook install_basic_services.yml
ansible-playbook install_shiny_server.yml
ansible-playbook install_rstudio_server.yml

Si decides que solo necesitas el servidor Shiny o el servidor RStudio pero no el otro, o si ya has instalado los servicios de soporte que deseas, puedes ejecutar solo los playbooks que necesitas.

Si deseas actualizar algo en el futuro, como R, RStudio o Shiny server (no puedo garantizar que siempre funcionará sin necesidad de cambios), puedes simplemente cambiar la versión en el archivo de configuración y ejecutar la parte específica del playbook aprovechando las “etiquetas” definidas.

Por ejemplo, esto solo instalará la versión R definida en el archivo de configuración y nada más:

cd raspberry_pi_server
ansible-playbook install_basic_services.yml --tags "r"

Las etiquetas disponibles son:

  • install_basic_services.yml
    • secure: Establecer la configuración de seguridad en el servidor
    • swap: Agregar memoria swap al servidor
    • nginx: Instalar y configurar Nginx + PHP
    • postgresql: Instalar y configurar PostgreSQL
    • r: Instalar R desde la fuente
    • disable_wifi: Desactivar el módulo Wifi y Bluetooth
  • install_shiny_server.yml
    • shiny-server: Instalar shiny-server desde la fuente
    • configure_shiny: Configurar shiny-server
  • install_rstudio_server.yml
    • rstudio: Instalar RStudio server desde la fuente
    • configure_rstudio: Configurar RStudio server

También puedes hacer lo contrario y omitir partes específicas de los playbooks usando la opción --skip-tags, por ejemplo, si no necesitas PostgreSQL, puedes evitar instalarlo ejecutando el playbook de esta manera:

cd raspberry_pi_server
ansible-playbook install_basic_services.yml --skip-tags "postgresql"

Después de ejecutar con éxito todos los playbooks, tendrás una instalación completamente funcional lista para ser utilizada, por lo que podras simplemente abrir una sesión de RStudio en http://ip_de_tu_servidor/rstudio y/o publicar tus aplicaciones Shiny en la carpeta /srv/shiny-server y acceder a ellas en http://ip_de_tu_servidor/shiny/nombre_de_tu_app.

⚠️ Si la configuración de Nginx no ha sido establecida por el playbook install_basic_services.yml porque lo has omitido, debes configurar el proxy inverso manualmente o acceder a los servicios con su puerto específico, por ejemplo http://your_server_ip/3838/your_app_name, esto también requiere que abras el puerto correspondiente en el firewall.

Notas Finales

Incluso con la automatización, la instalación de forma nativa llevará mucho más tiempo que, por ejemplo, con el uso de contenedores, especialmente si usas una Raspberry Pi con poca memoria RAM (< 4GB) pero como está automatizado, simplemente puedes dejar que se ejecute y volver más tarde, y disfrutarás de la facilidad de gestión de una instalación nativa.

Además, ten en cuenta que el proceso de instalación llevará tu Raspberry Pi a sus límites, por lo que puedes esperar algunos errores aleatorios, pero eso no significa que no va ha funcionar, simplemente reinicia tu Pi, vuelve a ejecutar el playbook problemático y ve si funciona la segunda vez. He hecho todo lo posible para que esto sea funcional a largo plazo estableciendo versiones de software específicas, pero aún es posible que una actualización de librerias del sistema inutilice los playbooks. Si encuentras algún problema, ve al repositorio de GitHub para los playbooks y registra un “issue”, o mejor aún, si sabes cómo solucionarlo, haz un “pull request”.

Como nota final, quiero señalar que este enfoque se puede extender aún más de acuerdo con tus propias necesidades, por ejemplo, puedes implementar la restauración automática de tu servidor, incluido el contenido desplegado. Por ejemplo, yo tengo un playbook adicional para restaurar las aplicaciones, servicios y bases de datos que normalmente ejecuto en mi Raspberry Pi, por lo que, en caso de una falla catastrófica, puedo volver a un estado operativo en un período corto de tiempo y con poco esfuerzo, comparado con hacer una restauración manual de mi sistema.

Edit this page
comments powered by Disqus