Bienvenidos a nuestra segunda entrega sobre tutoriales de .NET Core en Linux. En la entrada de hoy os explicaremos cómo compilar vuestro proyecto para que pueda ser ejecutado de forma nativa en las principales distribuciones Linux, sin necesidad de que el sistema destino soporte o tenga instalado .NET Core.
Antes de entrar en detalle, y por si os habéis perdido algún detalle, recordad que tenéis a vuestra disposición las otras entregas de esta serie:
Sin más preámbulo, empecemos:
"Despliegue autocontenido" es el nombre que recibe el proyecto compilado de una aplicación .NET Core que incluye todas las librerías y dependencias del framework necesarias para la ejecución de la aplicación.
Este acercamiento se diferencia del "Framework Dependent Deployment" que, como su nombre indica, requiere que la máquina destino disponga de una versión igual o superior al framework con el que se construyó.
Cada modelo tiene sus ventajas y desventajas. En concreto, los proyectos publicados como "autocontenidos" ofrecen mayor agilidad y flexibilidad al no necesitar la instalación adicional del framework. Incluso ofrecen mayores garantías de ejecución, asegurando que no habrá problemas de compatibilidad entre la aplicación y la versión del framework instalado, muchas veces desconocida.
En contrapartida, las builds autocontenidas no solo ocuparán más espacio, sino que deberán ser construidas específicamente para cada plataforma utilizando un "runtime identifier" que veremos en este tutorial. Cada persona o equipo deberá decidir qué modelo, SCD o FDD, se adecua más a las necesidades de su proyecto.
Veamos ahora cómo publicar y compilar un proyecto .NET Core para que sea ejecutado de forma nativa en Linux.
Veamos ahora cuáles son los pasos a seguir para que nuestro proyecto pueda ser ejecutado en las principales distribuciones Linux sin necesidad de instalar .NET Core.
En primer lugar deberás determinar si tu proyecto utiliza algún tipo de dependencia propio de la distribución que estés usando. Si bien las aplicaciones .NET Core "autocontenidas" hacen innecesario la instalación del framework en la máquina destino, es posible que tu aplicación sí use alguna otra dependencia exclusiva de tu distribución.
Antes de proceder a compilar la aplicación, deberás elegir un "runtime identifier" proporcionado por microsoft. El "runtime identifier" no es más que una cadena de texto que especifica al proceso de construcción y compilación cuál es la plataforma destino.
Algunos ejemplos incluyen:
linux-x64 (para cualquier distro x64
linux-arm (para distros sobre arquitectura ARM. Por ejemplo una Raspberry Pi)
debian-x64 (para distribuciones Debian)
debian.9-x64 (específico para Debian 9)
ubuntu-x64
ubuntu.18.04-x64
centos-x64
centos.7-x64
Por supuesto, si queréis construir vuestra aplicación para entornos Windows, macOS o Android también podéis utilizar los siguientes runtime identifiers:
win-x64 (para cualquier versión de windows)
win10-x64
osx-x64
osx.10.13-x64
android
Disponéis de una lista completa y actualizada de "runtime identifiers" en este archivo del proyecto .NET Core.
En todo caso, recordad que el runtime identifier no es una garantía 100% fiable de que la aplicación funcionará en la plataforma destino. Deberéis realizar las pruebas necesarias para asegurar que se cumplan todas las dependencias.
Finalmente ejecutamos el comando único que nos servirá para compilar nuestro proyecto como binario nativo de la plataforma que hayamos elegido.
En nuestro caso estamos trabajando sobre Ubuntu 18.04 y queremos compilar nuestro proyecto de ejemplo a un binario que funcione en versiones 64 bits de Linux, independientemente de la distro.
Para empezar, dirígete al directorio en el que se aloja tu proyecto.
cd miPrimerProyecto (en tu caso el nombre del directorio probablemente sea distinto)
A continuación, ejecutamos la siguiente línea de comando. Recordad que esta fallará si el compilador detecta errores durante el tiempo de compilado.
dotnet publish –o ../directorioDestino -c Release -r linux-x64
Os explicamos qué significa cada argumento:
-o: especifica el directorio destino.
-c: especifica la configuración o versión del proyecto. Podéis elegir entre Release y Debug.
-r: especifica el runtime identifier que os hemos mencionado antes.
Podéis consultar el resto de argumentos disponibles ejecutando "dotnet publish --help".
Una vez haya finalizado el proceso de compilado, dirigiros al directorio destino que hayáis especificado.
cd ../directorioDestino
Y listamos los contenidos:
ls
Si todo ha ido bien, deberíais ver que el directorio contiene una cincuentena de archivos entre los que destacan los archivos .dll y .so que hacen referencia al propio framework .NET core. Es decir, son las librerías necesarias para ejecutar la aplicación.
Finalmente, solo nos quedará probar la aplicación ejecutando el binario nativo designado con el nombre de vuestro proyecto.
./miPrimerProyecto
Llegado a este punto deberías ver cómo tu proyecto se ejecuta correctamente, por ejemplo, mostrando el famoso "Hello world!" si seguiste nuestro tutorial anterior. ¡Enhorabuena!
¿Pero qué hay de otras distribuciones? En el apartado anterior sólo probamos de ejecutar nuestra aplicación en el mismo sistema en que lo compilamos, sistema que además tiene instalado .NET Core. ¿Podemos estar seguros que la aplicación realmente funcionará en otras distribuciones? ¡Buena pregunta!
Para salir de dudas haremos lo siguiente: desplegar 4 servidores Cloud ONE con distros distintas. Probaremos nuestra aplicación en cada uno de estos servidores y verificaremos que se ejecute incluso en distribuciones tan distintas entre ellas como Debian, CentOS u Oracle Linux.
En este caso utilizaremos nuestros servidores Cloud One, un tipo de instancia que se despliega en cinco minutos y que se factura por horas, pagando solo por el tiempo que necesitemos en realizar las pruebas. Si tenéis curiosidad sobre servidores Cloud para entornos de desarrollo o producción, os dejamos aquí el enlace a nuestra página de servidores Cloud.
Si sois clientes de SW, sólo deberéis seleccionar el tipo de instancia que queréis crear desde vuestro SW Panel. En caso contrario, cread una máquina virtual con la distro que queráis probar en vuestro proveedor.
Para distribuir la aplicación entre distintas instancias Cloud crearemos temporalmente un repositorio de GIT y lo clonaremos directamente desde las distribuciones destino. Estos pasos presuponen que tenéis experiencia con GIT.
Una vez desplegados los servidores Cloud, así queda nuestro entorno de pruebas:
Instalamos GIT mediante APT o YUM y clonamos el repositorio en cada uno de los servidores.
apt-get install git || yum install git
git clone https://github.com/miusuario/mirepositorio
Entramos en el directorio de nuestro proyecto
cd mirepositorio
Y finalmente tratamos de ejecutar nuestra aplicación desde las distintas distros:
./miPrimerProyecto
Si todo ha ido bien, deberéis ver cómo vuestra aplicación se ejecuta exitosamente en una instancia totalmente nueva y sin rastro de .Net Core o cualquier dependencia.
Por ejemplo, durante nuestras pruebas nos hemos encontrado con el siguiente error en máquinas con CentOS u Oracle Linux:
FailFast: Couldn't find a valid ICU package installed on the system.
Set the configuration flag System.Globalization.
Invariant to true if you want to run with no globalization support.
Esencialmente significa que compliar nuestras aplicaciones .NET Core a binarios nativos hace innecesario el framework pero no así el resto de librerías o dependencias que un proyecto pudiera requerir.
En este caso el problema se soluciona instalando la librería "libicu" para internacionalización.
yum install libicu.x86_64
Por lo tanto es importante que realicéis los tests pertinentes y documentéis bien las librerías o dependencias necesarias para vuestras aplicaciones.
Anteriormente hemos mencionado los distintos runtime identifiers que podéis utilizar para compilar vuestras aplicaciones. No viene ma recordar que podéis compilar aplicaciones para cualquier plataforma desde cualquier plataforma. Esto significa que un desarrollador en Linux puede compilar su proyecto para todas las demás plataformas, sin necesidad de disponer de ellas.
Obviamente si no tenemos acceso a la plataforma destino no podremos realizar nosotros mismos los tests pertinentes, pero aún así esta posibildad nos aportará mucha flexibilidad y agilidad a la hora de publicar las aplicaciones.
Esperamos que os haya gustado este tutorial.
Acompañadnos de nuevo en la próxima entrada donde explicaremos cómo crear y configurar una aplicación en ASP.NET Core con MVC detrás de un proxy inverso de Apache o Nginx.
Y como siempre, recordad que si estáis buscando un lugar donde desarrollar vuestra nueva aplicación .NET Core y necesitáis un entorno altamente estable, podéis hacerlo con nuestros servidores Cloud especializados para entornos críticos o que requieran alta disponibilidad.
¡Saludos y hasta la próxima!