Ahora Suitecoffee puede correr dentro de contenedores docker. Mediante docker compose sin necesidad de exponer puertos, únicamente se expone un puerto 80 del servicio 'gateway' que utiliza una imagen nginx:alpine.
el comando para levantar el servicio con el entorno de desarrollo (utilizando las variables desarrollo + docker.compose.override.yml) es: docker compose -f docker-compose.yml -f docker-compose.override.yml --env-file .env.development up -d Para desactivarlo: docker compose -f docker-compose.yml -f docker-compose.override.yml --env-file .env.development down
This commit is contained in:
parent
abaf43b8d6
commit
3d3ef3f002
@ -2,73 +2,117 @@
|
||||
# Docker Comose para entorno de desarrollo o development.
|
||||
|
||||
services:
|
||||
gateway:
|
||||
image: nginx:alpine
|
||||
container_name: suitecoffee-gateway
|
||||
depends_on:
|
||||
suitecoffee-app:
|
||||
condition: service_healthy
|
||||
suitecoffee-auth:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "80:80" # único puerto público (agregá 443 si después sumás TLS)
|
||||
volumes:
|
||||
- ./gateway/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
networks:
|
||||
- suitecoffee-net
|
||||
restart: unless-stopped
|
||||
|
||||
suitecoffee-app:
|
||||
container_name: suitecoffee-app
|
||||
depends_on:
|
||||
- suitecoffee-db
|
||||
- suitecoffee-tenants
|
||||
suitecoffee-db:
|
||||
condition: service_healthy
|
||||
suitecoffee-tenants:
|
||||
condition: service_healthy
|
||||
build:
|
||||
context: ./services/app
|
||||
dockerfile: Dockerfile.development
|
||||
volumes:
|
||||
- ./services/app:/app
|
||||
ports:
|
||||
- ${APP_LOCAL_PORT}:${APP_DOCKER_PORT}
|
||||
# env_file:
|
||||
# -
|
||||
env_file:
|
||||
- ./services/app/.env.development
|
||||
environment:
|
||||
- NODE_ENV=${NODE_ENV}
|
||||
command: npm run dev
|
||||
healthcheck:
|
||||
# IMPORTANTE: asegurate de tener curl instalado en la imagen de app (ver nota abajo)
|
||||
test: ["CMD-SHELL", "curl -fsS http://localhost:${APP_DOCKER_PORT}/health || exit 1"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
start_period: 20s
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- suitecoffee-net
|
||||
|
||||
suitecoffee-auth:
|
||||
container_name: suitecoffee-auth
|
||||
depends_on:
|
||||
- suitecoffee-auth-db
|
||||
suitecoffee-db:
|
||||
condition: service_healthy
|
||||
build:
|
||||
context: ./services/auth
|
||||
dockerfile: Dockerfile.development
|
||||
volumes:
|
||||
- ./services/auth:/app
|
||||
ports:
|
||||
- ${AUTH_LOCAL_PORT}:${AUTH_DOCKER_PORT}
|
||||
# env_file:
|
||||
# -
|
||||
env_file:
|
||||
- ./services/auth/.env.development
|
||||
environment:
|
||||
- NODE_ENV=${NODE_ENV}
|
||||
command: npm run dev
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -fsS http://localhost:${AUTH_DOCKER_PORT:-4000}/health || exit 1"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
start_period: 15s
|
||||
networks:
|
||||
- suitecoffee-net
|
||||
|
||||
suitecoffee-db:
|
||||
image: postgres:16
|
||||
container_name: suitecoffee-db
|
||||
# env_file:
|
||||
# -
|
||||
environment:
|
||||
POSTGRES_DB: ${DB_NAME}
|
||||
POSTGRES_USER: ${DB_USER}
|
||||
POSTGRES_PASSWORD: ${DB_PASS}
|
||||
ports:
|
||||
- ${DB_LOCAL_PORT}:${DB_DOCKER_PORT}
|
||||
volumes:
|
||||
- suitecoffee-data:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 20
|
||||
start_period: 10s
|
||||
networks:
|
||||
- suitecoffee-net
|
||||
|
||||
suitecoffee-tenants:
|
||||
suitecoffee-tenants:
|
||||
image: postgres:16
|
||||
container_name: suitecoffee-tenants
|
||||
# env_file:
|
||||
# -
|
||||
environment:
|
||||
POSTGRES_DB: ${TENANTS_DB_NAME}
|
||||
POSTGRES_USER: ${TENANTS_DB_USER}
|
||||
POSTGRES_PASSWORD: ${TENANTS_DB_PASS}
|
||||
ports:
|
||||
- ${TENANTS_DB_LOCAL_PORT}:${TENANTS_DB_DOCKER_PORT}
|
||||
volumes:
|
||||
- tenants-data:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${TENANTS_DB_USER} -d ${TENANTS_DB_NAME}"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 20
|
||||
start_period: 10s
|
||||
networks:
|
||||
- suitecoffee-net
|
||||
|
||||
volumes:
|
||||
tenants-data:
|
||||
suitecoffee-data:
|
||||
suitecoffee-data:
|
||||
|
||||
networks:
|
||||
suitecoffee-net:
|
||||
driver: bridge
|
||||
49
gateway/nginx.conf
Normal file
49
gateway/nginx.conf
Normal file
@ -0,0 +1,49 @@
|
||||
worker_processes 1;
|
||||
|
||||
events { worker_connections 1024; }
|
||||
|
||||
http {
|
||||
# Logs básicos
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log;
|
||||
|
||||
# Ajustes útiles para proxys
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Connection "";
|
||||
|
||||
# Soporte WebSocket (si lo usás en dev)
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
# Frontend / App principal (Next/React/Express, etc.)
|
||||
# / -> app
|
||||
location / {
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_pass http://suitecoffee-app:4000; # usa el puerto interno de app
|
||||
}
|
||||
|
||||
# API de app (si preferís separar por path)
|
||||
location /api/ {
|
||||
proxy_pass http://suitecoffee-app:3000;
|
||||
}
|
||||
|
||||
# Servicio de autenticación (por ejemplo /auth/*)
|
||||
# location /auth/ {
|
||||
# proxy_pass http://suitecoffee-auth:4000;
|
||||
# }
|
||||
|
||||
# Opcional: servir estáticos si la app build genera /public
|
||||
# location /static/ { alias /usr/share/nginx/html/static/; }
|
||||
}
|
||||
}
|
||||
1482
package-lock.json
generated
Normal file
1482
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
5
package.json
Normal file
5
package.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"app": "file:services/app"
|
||||
}
|
||||
}
|
||||
@ -9,8 +9,9 @@ ARG PORT=3000
|
||||
COPY package*.json ./
|
||||
|
||||
# Instala dependencias
|
||||
RUN npm i express pg dotenv cors
|
||||
RUN npm i --save-dev nodemon
|
||||
RUN apt-get update
|
||||
RUN npm i
|
||||
RUN apt-get install -y curl && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copia el resto de la app
|
||||
COPY . .
|
||||
|
||||
13
services/app/package-lock.json
generated
13
services/app/package-lock.json
generated
@ -9,6 +9,7 @@
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"chalk": "^5.3.0",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^17.2.1",
|
||||
"express": "^5.1.0",
|
||||
@ -145,6 +146,18 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.5.0.tgz",
|
||||
"integrity": "sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^12.17.0 || ^14.13 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
|
||||
@ -19,7 +19,8 @@
|
||||
"dotenv": "^17.2.1",
|
||||
"express": "^5.1.0",
|
||||
"express-ejs-layouts": "^2.5.1",
|
||||
"pg": "^8.16.3"
|
||||
"pg": "^8.16.3",
|
||||
"chalk": "^5.3.0"
|
||||
},
|
||||
"keywords": [],
|
||||
"description": ""
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
// app/src/index.js
|
||||
import chalk from 'chalk'; // Colores!
|
||||
import express from 'express';
|
||||
import expressLayouts from 'express-ejs-layouts';
|
||||
import cors from 'cors';
|
||||
@ -17,13 +18,13 @@ import dotenv, { config } from 'dotenv';
|
||||
try {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
dotenv.config({ path: path.resolve(__dirname, '../.env.development' )});
|
||||
console.log("Activando entorno de -> development");
|
||||
console.log(`Activando entorno de ->${chalk.green(` DEVELOPMENT `)}`);
|
||||
} else if (process.env.NODE_ENV === 'stage') {
|
||||
dotenv.config({ path: path.resolve(__dirname, '../.env.test' )});
|
||||
console.log("Activando entorno de -> testing");
|
||||
console.log(`Activando entorno de ->->${chalk.yellow(` TESTING `)}`);
|
||||
} else if (process.env.NODE_ENV === 'production') {
|
||||
dotenv.config({ path: path.resolve(__dirname, '../.env' )});
|
||||
console.log("Activando entorno de -> producción");
|
||||
console.log(`Activando entorno de ->->${chalk.red(` PRODUCTION `)}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("A ocurrido un error al seleccionar el entorno. \nError: " + error);
|
||||
@ -51,16 +52,17 @@ async function verificarConexion() {
|
||||
try {
|
||||
const client = await pool.connect();
|
||||
const res = await client.query('SELECT NOW() AS hora');
|
||||
console.log('Conexión con la base de datos fue exitosa.');
|
||||
console.log(`\nConexión con la base de datos ${chalk.green(process.env.DB_NAME)} fue exitosa.`);
|
||||
console.log('Fecha y hora actual de la base de datos:', res.rows[0].hora);
|
||||
client.release(); // liberar el cliente de nuevo al pool
|
||||
} catch (error) {
|
||||
console.error('Error al conectar con la base de datos al iniciar:', error.message);
|
||||
console.error(`Troubleshooting:\n1. Compruebe que las bases de datos se iniciaron correctamente.\n2. Verifique las credenciales y puertos de acceso a la base de datos.\n3. Si está conectandose a una base de datos externa a localhost, verifique las reglas del firewal de entrada y salida de ambos dispositivos.`);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// === Servir páginas estáticas ===
|
||||
app.use('/pages', express.static(path.join(__dirname, 'pages')));
|
||||
|
||||
@ -231,10 +233,21 @@ async function q(text, params) {
|
||||
});
|
||||
|
||||
|
||||
// Colores personalizados
|
||||
let primaryColor = chalk.hex('#'+`${process.env.COL_PRI}`);
|
||||
let secondaryColor = chalk.hex('#'+`${process.env.COL_SEC}`);
|
||||
// let backgroundColor = chalk.hex('#'+`${process.env.COL_BG}`);
|
||||
|
||||
|
||||
app.use(expressLayouts);
|
||||
// Iniciar servidor
|
||||
app.listen( process.env.PORT, () => {
|
||||
console.log(`Servidor corriendo en http://localhost:${process.env.PORT}`);
|
||||
console.log('Estableciendo conexión con la db...');
|
||||
console.log(`Servidor de ${chalk.red('aplicación')} de ${secondaryColor('SuiteCoffee')} corriendo en ${chalk.yellow(`http://localhost:${process.env.PORT}\n`)}` );
|
||||
console.log(chalk.grey(`Comprobando accesibilidad a la db ${chalk.green(process.env.DB_NAME)} del host ${chalk.white(`${process.env.DB_HOST}`)} ...`));
|
||||
verificarConexion();
|
||||
});
|
||||
|
||||
app.get("/health", async (req, res) => {
|
||||
// Podés chequear DB aquí. 200 = healthy; 503 = not ready.
|
||||
res.status(200).json({ status: "ok" });
|
||||
});
|
||||
@ -3,20 +3,21 @@ FROM node:20.17
|
||||
|
||||
# Definir variables de entorno con valores predeterminados
|
||||
ARG NODE_ENV=development
|
||||
ARG PORT=3000
|
||||
ARG PORT=4000
|
||||
|
||||
# Copia archivos de configuración primero para aprovechar el cache
|
||||
COPY package*.json ./
|
||||
|
||||
# Instala dependencias
|
||||
RUN npm i express pg dotenv cors
|
||||
RUN npm i --save-dev nodemon
|
||||
RUN apt-get update
|
||||
RUN npm i
|
||||
RUN apt-get install -y curl && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copia el resto de la app
|
||||
COPY . .
|
||||
|
||||
# Expone el puerto
|
||||
EXPOSE 3000
|
||||
EXPOSE 4000
|
||||
|
||||
# Usa nodemon para hot reload si lo tenés
|
||||
CMD ["npm", "run", "dev"]
|
||||
13
services/auth/package-lock.json
generated
13
services/auth/package-lock.json
generated
@ -10,6 +10,7 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"bcrypt": "^5.1.1",
|
||||
"chalk": "^5.3.0",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^17.2.1",
|
||||
"express": "^5.1.0",
|
||||
@ -236,6 +237,18 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.5.0.tgz",
|
||||
"integrity": "sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^12.17.0 || ^14.13 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
|
||||
@ -20,7 +20,8 @@
|
||||
"express": "^5.1.0",
|
||||
"express-ejs-layouts": "^2.5.1",
|
||||
"pg": "^8.16.3",
|
||||
"bcrypt": "^5.1.1"
|
||||
"bcrypt": "^5.1.1",
|
||||
"chalk": "^5.3.0"
|
||||
},
|
||||
"keywords": [],
|
||||
"description": ""
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
// auth/src/index.js
|
||||
import chalk from 'chalk'; // Colores!
|
||||
import express from 'express';
|
||||
import expressLayouts from 'express-ejs-layouts';
|
||||
import cors from 'cors';
|
||||
@ -18,13 +19,13 @@ import dotenv, { config } from 'dotenv';
|
||||
try {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
dotenv.config({ path: path.resolve(__dirname, '../.env.development' )});
|
||||
console.log("Activando entorno de -> development");
|
||||
console.log(`Activando entorno de ->${chalk.green(` DEVELOPMENT `)}`);
|
||||
} else if (process.env.NODE_ENV === 'stage') {
|
||||
dotenv.config({ path: path.resolve(__dirname, '../.env.test' )});
|
||||
console.log("Activando entorno de -> testing");
|
||||
console.log(`Activando entorno de ->->${chalk.yellow(` TESTING `)}`);
|
||||
} else if (process.env.NODE_ENV === 'production') {
|
||||
dotenv.config({ path: path.resolve(__dirname, '../.env' )});
|
||||
console.log("Activando entorno de -> producción");
|
||||
console.log(`Activando entorno de ->->${chalk.red(` PRODUCTION `)}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("A ocurrido un error al seleccionar el entorno. \nError: " + error);
|
||||
@ -52,11 +53,12 @@ async function verificarConexion() {
|
||||
try {
|
||||
const client = await pool.connect();
|
||||
const res = await client.query('SELECT NOW() AS hora');
|
||||
console.log('Conexión con la base de datos fue exitosa.');
|
||||
console.log(`\nConexión con la base de datos ${chalk.green(process.env.DB_NAME)} fue exitosa.`);
|
||||
console.log('Fecha y hora actual de la base de datos:', res.rows[0].hora);
|
||||
client.release(); // liberar el cliente de nuevo al pool
|
||||
} catch (error) {
|
||||
console.error('Error al conectar con la base de datos al iniciar:', error.message);
|
||||
console.error(`Troubleshooting:\n1. Compruebe que las bases de datos se iniciaron correctamente.\n2. Verifique las credenciales y puertos de acceso a la base de datos.\n3. Si está conectandose a una base de datos externa a localhost, verifique las reglas del firewal de entrada y salida de ambos dispositivos.`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,14 +182,21 @@ app.post('/login', async (req, res) => {
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
// Colores personalizados
|
||||
let primaryColor = chalk.hex('#'+`${process.env.COL_PRI}`);
|
||||
let secondaryColor = chalk.hex('#'+`${process.env.COL_SEC}`);
|
||||
// let backgroundColor = chalk.hex('#'+`${process.env.COL_BG}`);
|
||||
|
||||
|
||||
app.use(expressLayouts);
|
||||
// Iniciar servidor
|
||||
app.listen( process.env.PORT, () => {
|
||||
console.log(`Servidor corriendo en http://localhost:${process.env.PORT}`);
|
||||
console.log('Estableciendo conexión con la db...');
|
||||
console.log(`Servidor de ${chalk.yellow('autenticación')} de ${secondaryColor('SuiteCoffee')} corriendo en ${chalk.yellow(`http://localhost:${process.env.PORT}\n`)}` );
|
||||
console.log(chalk.grey(`Comprobando accesibilidad a la db ${chalk.green(process.env.DB_NAME)} del host ${chalk.white(`${process.env.DB_HOST}`)} ...`));
|
||||
verificarConexion();
|
||||
});
|
||||
|
||||
app.get("/health", async (req, res) => {
|
||||
// Podés chequear DB aquí. 200 = healthy; 503 = not ready.
|
||||
res.status(200).json({ status: "ok" });
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user