Crear un CD con github action, EC2 y express
3 min read

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.sh

Primero 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