DEV Community

GoyesDev
GoyesDev

Posted on

Publicar servicio basado en VAPOR en DigitalOcean

Crear y configurar servidor en DigitalOcean

Para empezar hay que crear un droplet

Creando droplet

Elegir la distribución como Linux Ubuntu 22.04 LTS (hay más recientes, pero ir a la fija con 22.04 LTS)

Linux distribution

Escoger el tamaño del servidor que haga falta. En mi caso, me sirve un procesador regular de un solo núcleo, 512 MB de ram y 10GB de disco:

Escogiendo tamaño

Elegir la forma de autentificación contra el servidor. Yo quiero usar SSH, así que antes tuve que instalar una llave SSH en DigitalOcean

Auth methods

Especifico el nombre del servidor y lo asocio a un proyecto:

Final steps

Al final, acepto crear el servidor con la configuración especificada

Esperamos hasta que termine de crear el servidor


Ubicar la IP del servidor

Eventualmente el servidor terminará de crear y podremos ver la IP en el mismo panel:

Adicionalmente, en el panel de la izquierda aparecerán nuestros proyectos. Vamos allá y buscamos el proyecto al que agregamos el droplet:


Configurar el servidor

Conectándonos al servidor

Vamos a conectarnos por SSH al servidor así:

ssh root@your_server_ip
Enter fullscreen mode Exit fullscreen mode

En este ejemplo yo tendría que reemplazar your_server_ip por 146.190.121.34.

Nos va a preguntar si reconocemos la conexión y queremos guardar la firma:

Configuramos firewall

Activamos OpenSSH

ufw allow OpenSSH
ufw enable
Enter fullscreen mode Exit fullscreen mode

Cuando nos pregunte si estamos seguros, le damos y:

Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

Abrimos el puerto 8080 para después

sudo ufw allow 8080
Enter fullscreen mode Exit fullscreen mode

Rule added


Crear un usuario en el servidor

Adicional a root vamos a crear un usuario llamado vapor. Al introducir el siguiente comando nos va a pedir introducir una contraseña y confirmación de contraseña (deben coincidir). Luego, nos va a pedir una información adicional que se puede dejar en blanco (Full Name, Room Number, Work Phone, Home Phone y Other). Nos va a pedir que confirmemos y vamos a poner Y.

adduser vapor
Enter fullscreen mode Exit fullscreen mode

Permitir que vapor use sudo:

usermod -aG sudo vapor
Enter fullscreen mode Exit fullscreen mode

Copiar las llaves SSH autorizadas del usuario root a vapor, para poder entrar con SSH a este usuario:

rsync --archive --chown=vapor:vapor ~/.ssh /home/vapor
Enter fullscreen mode Exit fullscreen mode

Cerramos la sesión y entramos como el nuevo usuario:

exit
ssh vapor@your_server_ip
Enter fullscreen mode Exit fullscreen mode

Instalamos Swift en el servidor

Primero hay que instalar Swiftly en Linux para gestionar las versiones de Swift:

curl -O https://download.swift.org/swiftly/linux/swiftly-$(uname -m).tar.gz && \
tar zxf swiftly-$(uname -m).tar.gz && \
./swiftly init --quiet-shell-followup && \
. "${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}/env.sh" && \
hash -r
Enter fullscreen mode Exit fullscreen mode

Nos va a pedir confirmación, así que le damos Y:

Es probable que después de terminar diga que hacen falta algunas dependencias para continuar:

Las vamos a instalar con apt-get:

sudo apt-get update; sudo apt-get -y install binutils unzip libcurl4-openssl-dev libgcc-13-dev libpython3-dev libstdc++-13-dev libxml2-dev libncurses-dev libz3-dev pkg-config zlib1g-dev
Enter fullscreen mode Exit fullscreen mode

Cuando termine, verificamos la versión de Swift instalada

swift --version
Enter fullscreen mode Exit fullscreen mode

Swift version 6.2.3 (swift-6.2.3-RELEASE)
Target: x86_64-unknown-linux-gnu


Instalar VAPOR

Clonamos el toolbox de vapor

git clone https://github.com/vapor/toolbox.git
Enter fullscreen mode Exit fullscreen mode

Hacemos checkout del último release, que en la fecha es 20.0.0:

cd toolbox
git checkout 20.0.0
Enter fullscreen mode Exit fullscreen mode

Se compila vapor y se mueve el binario al path

swift build -c release --disable-sandbox
sudo mv .build/release/vapor /usr/local/bin
Enter fullscreen mode Exit fullscreen mode

Cuando termine de compilar, se puede borrar el toolbox:

cd ..
rm -rf toolbox
Enter fullscreen mode Exit fullscreen mode

Compilar el repositorio en el servidor

Clonar el repositorio. Para que esto funcione, es necesario instalar una llave SSH del servidor en Github:

git clone git@github.com:<reponame>.git
Enter fullscreen mode Exit fullscreen mode

Luego moverse al directorio del repositorio:

cd StripeIntentService
Enter fullscreen mode Exit fullscreen mode

Compilar (solamente) la aplicación:

swift build -v
Enter fullscreen mode Exit fullscreen mode

Para este paso es posible que haga falta cambiar las dimensiones (RAM) del droplet a 4GB. Después de que termine de compilar, se puede volver a reducir.

Esperar hasta que el servidor acabe. Puede demorarse una eternidad. En un droplet de DigitalOcean con 4GB de RAM y 1 procesador, la compilación de un servicio SUPER SIMPLE que usa Stripe se demoró 17 minutos.

(...) needed" "-lgcc_s" "--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "/usr/lib/gcc/x86_64-linux-gnu/13/crtendS.o" "/lib/x86_64-linux-gnu/crtn.o" (end of response file) Build complete! (1018.37s)

Luego se ejecuta el servicio que ya está compilado. NO usar swift run sino directamente:

.build/debug/StripeIntentService serve --hostname 0.0.0.0 --port 8080
Enter fullscreen mode Exit fullscreen mode

Instalar llave SSH del servidor en Github

En el servidor, crear una llave SSH. En el siguiente comando reemplazar "your_email@example.com" con el correo que haga falta. Cuando pregunte por ubicación y contraseña, vamos a ir con las opciones por defecto:

ssh-keygen -t ed25519 -C "your_email@example.com"
Enter fullscreen mode Exit fullscreen mode

Empezar el agente ssh en segundo plano:

eval "$(ssh-agent -s)"
Enter fullscreen mode Exit fullscreen mode

Modificar ~/.ssh/config con nano:

nano ~/.ssh/config
Enter fullscreen mode Exit fullscreen mode

Agregar la configuración para usar la llave en github. Cuidado de no poner la instrucción UseKeychain yes que solo funciona en macos:

Host github.com
  AddKeysToAgent yes
  IdentityFile ~/.ssh/id_ed25519
Enter fullscreen mode Exit fullscreen mode

Agregar la llave SSH al agente. Cuidado de no usar --apple-use-keychain que solo funciona en MacOS:

ssh-add ~/.ssh/id_ed25519
Enter fullscreen mode Exit fullscreen mode

Imprimir en consola el valor de la llave:

cat ~/.ssh/id_ed25519.pub
Enter fullscreen mode Exit fullscreen mode

Se copia la llave y se pega en Github.

Cambiar dimensiones del droplet

La configuación de 512MB de ram puede no ser suficiente para compilar la aplicación. En ese caso, hay que cambiar las dimensiones del droplet.

Buscar en el panel izquierdo de "manage" la opción "Droplets":

E ir directamente al botón "Upsize"

Allí se buscan las dimensiones que hagan falta, como 2GB de RAM

Se hace clic en ella, y luego "Resize"

Troubleshooting

Fatal error: Missing STRIPE_SECRET_KEY

En caso de que se use alguna variable de ambiente, recordar crearlas en un archivo .env. De lo contrario, fallará en la compilación.

Disparo la compilación con swift build, pero se queda congelado

¿El proceso está corriendo?

Primero hay que detectar si el proceso sigue corriendo. Para ello, se crea otra conexión SSH al servidor y se mira si hay algún proceso con el mismo nombre que el servicio compilado.

ps aux | grep StripeIntentService
Enter fullscreen mode Exit fullscreen mode

La respuesta podría ser algo como esto:

vapor 2100 0.3 0.8 74268 17704 ? Sl 13:35 0:00 swift run StripeIntentService serve --hostname 0.0.0.0 --port 8080 vapor 2107 0.7 6.4 726968 129616 ? Sl 13:35 0:01 /home/vapor/.local/share/swiftly/toolchains/6.2.3/usr/bin/swift-run StripeIntentService serve --hostname 0.0.0.0 --port 8080 vapor 2195 0.0 0.1 6680 2340 pts/1 S+ 13:38 0:00 grep --color=auto StripeIntentService
Enter fullscreen mode Exit fullscreen mode

Las siguientes líneas indican que la compilación está en curso:

2100  swift run StripeIntentService ...
2107  swift-run StripeIntentService ...
Enter fullscreen mode Exit fullscreen mode

Si es necesario detener los procesos se hace:

kill 2100 2107
Enter fullscreen mode Exit fullscreen mode

¿El servicio está escuchando en el puerto?

Comprobar si el puerto 8080 está abierto y escuchando:

ss -tulpn | grep 8080
Enter fullscreen mode Exit fullscreen mode

Debería traer algo como

LISTEN  0  128  0.0.0.0:8080
Enter fullscreen mode Exit fullscreen mode

Si no trae nada, es porque el servicio no está escuchando

Ejecutar compilación mostrando todos los logs

Se puede usar el modificador -v para mostrar los logs

swift build -v
Enter fullscreen mode Exit fullscreen mode

Si se queda colgado en "Planning build" es porque hay un problema con SPM:

(...) -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/13/crtendS.o /lib/x86_64-linux-gnu/crtn.o Planning build

La app no se está ejecutando todavía. La compilación está atascada en la fase de resolución / planificación de Swift Package Manager. SPM está tratando de resolver dependencias, validar el grafo, posiblemente acceder a red (si cree que debe actualizar algo) o está bloqueado por cache corrupta.

Esto puede ocurrir cuando:

  1. Hay un problema con el cache en ~/.swiftpm
  2. Hay conflicto con swiftly
  3. Hay un repo de dependencia que quedó corrupto

Para solucionarlo, primero hay que matar los procesos en cursos. Para ello, crear otra conexión ssh, mostrar los procesos que usen StripeIntentService o directamente:

killall -9 swift
killall -9 swift-run
Enter fullscreen mode Exit fullscreen mode

Luego, dentro del directorio del proyecto:

swift package clean
rm -rf .build
rm -rf Package.resolved
Enter fullscreen mode Exit fullscreen mode

También limpiar la caché global:

rm -rf ~/.swiftpm
rm -rf ~/StripeIntentService/.build
Enter fullscreen mode Exit fullscreen mode

Aunque es una solución agresiva (limpiar todo), me funcionó.

Luego, volver a compilar con -v y mirar si el error persiste:

swift build -v
Enter fullscreen mode Exit fullscreen mode

Top comments (0)