Crear un CD con github action, EC2 y express
La idea es crear un CD básico que se va a encargar de cuando nosotros hagamos push de un cambio en github este dispare una acción la cual va a hacer que nuestro servidor se traiga estos cambios y deploye una nueva versión de la aplicación.
Primero iniciamos una EC2 con Ubuntu, (aca vamos a usar un EC2 de AWS, pero se puede usar cualquier otro proveedor), luego una vez conectado a la máquina seguimos los siguientes pasos
Instalar NGNIX
sudo apt-get install nginx
Ahora tenemos que configurar que las request que reciba la máquina se redireccionen al localhost donde va a estar escuchando nuestra aplicacion.
Entonces creamos un archivo carpeta /etc/nginx/conf.d con el nombre expressapi.conf (es muy importante el .conf porque si no NGNIX no va a leer el archivo desde esta carpeta)
server {
listen 80;
listen [::]:80;
server_name 23.....; # Aca ponene la ip de la maquina su dominio
location / {
proxy_pass <http://localhost:3001/>; #Este va a ser el puerto donde levantemos la API de express
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Real-IP $remote_addr;
}
}
Después instalamos pm2, con pm2 vamos a poder levantar el proceso de node y si ocurre algun inconveniente y el proceso se cae, pm2 se va a encargar de volver a levantar la aplicación.
npm install pm2@latest -g
Después generamos la task en pm2, tener en cuenta aca que run prod corre un script configurado en el package.json.
# npm run prod ---> corremos este comando con pm2
pm2 start npm --name "expressApi" -- run prod
Con esto va a quedar la API corriendo si vemos con pm2 list
pm2 list
┌─────┬────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │
├─────┼────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0 │ expressApi │ default │ N/A │ fork │ 3692 │ 86s │ 0 │ online │ 0% │ 43.3mb │ ubuntu │ disabled │
# Lo bueno de esto es que ahora haciendo
pm2 stop expressApi
pm2 start expressApi
Podemos apagar y prender la api
Algo que me es muy útil cuando uso pm2 es crear una cuenta en su monitor de aplicaciones y sincronizar la misma con el servidor, esto nos brinda un monitor para poder ver la consola y el output de toda la aplicación, también nos muestra métricas sobre el servidor y el consumo de recursos de la aplicación.
Generar SSH key para poder traer cambios de git sin usar el user
ssh-keygen -t rsa -b 4096 -C "githubemail@gmail.com"
ls ~/ssh
Para copiar la clave
cat .ssh/id_rsa.pub
Una vez copiada la clave, voy y la habilito en GitHub en https://github.com/settings/keys
Crear archivo en raíz de el servidor
Creamos un archivo en la raíz de la máquina llamado deploy.sh y escribimos lo siguiente
cd express-api
git pull
# npm install
pm2 stop expressApi
pm2 start expressApi
La idea de este sh es que después que mediante una GitHub Action se corra y actualice la aplicación.
Configurar GitHub Action
La idea de esto es "simular" si entráramos al servidor y corriéramos el archivo deploy.sh, si actualizáramos la aplicación desde nuestra máquina local deberíamos hacer lo siguiente.
ssh -i "PROD_KEY" PROD_USERNAME@PROD_HOST
sh deploy.shPrimero vamos a generar claves secretas dentro del repositorio para poder guardar las claves de la conexión al servidor.
Nos dirigimos a la settings de el repositorio, luego a Secrets -> Actions y aqui generamos tres claves con sus respectivos valores
PROD_HOST
PROD_KEY
PROD_USERNAME
Luego creamos un archivo en el repositorio en el root .github/workflows/file.yml
name: deploy-prod
on:
push:
branches:
- master
jobs:
build:
name: Deploy production
runs-on: ubuntu-18.04
steps:
- name: run sh
uses: garygrossgarten/github-action-ssh@release
with:
command: sh deploy.sh
host: ${{ secrets.PROD_HOST }}
username: ${{ secrets.PROD_USERNAME }}
privateKey: ${{ secrets.PROD_KEY}}
Luego pusheamos el archivo directo a master y en la parte de Github Actions vemos lo siguiente
