diff --git a/docker-compose.yml b/docker-compose.yml index 58ce40a..a3bec84 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,18 +1,15 @@ networks: - transcendance-network: + app: driver: bridge monitoring: driver: bridge services: - ############### - # USER # - ############### frontend: build: ./frontend - container_name: frontend + container_name: app-frontend restart: on-failure:3 networks: - - transcendance-network + - app volumes: - static-volume:/volumes/static logging: @@ -21,20 +18,16 @@ services: gelf-address: "udp://127.0.0.1:12201" tag: "{{.Name}}" - # - # The "entry point" as in it does all of this: - # - serve files (images, static files, video) - # - redirect request to appropirate service (reverse proxy) - # - be the one that handles TLS/SSL (basically HTTPS) - # - other stuff I don't know yet nginx: build: ./nginx - container_name: nginx + container_name: app-nginx restart: always networks: - - transcendance-network + - app + - monitoring ports: - '8888:443' + - '9090:8443' volumes: # if you need to share files with nginx, you do it here. - static-volume:/volumes/static @@ -48,18 +41,19 @@ services: tag: "{{.Name}}" ############### - # AUTH # + # SERVICE # ############### + auth: build: context: ./src/ args: - SERVICE=auth - EXTRA_FILES=auth/extra - container_name: auth + container_name: app-auth restart: always networks: - - transcendance-network + - app volumes: - sqlite-volume:/volumes/database - static-volume:/volumes/static @@ -73,39 +67,15 @@ services: gelf-address: "udp://127.0.0.1:12201" tag: "{{.Name}}" - ############### - # TIC-TAC-TOE # - ############### - # tic-tac-toe: - # build: - # context: ./src/ - # args: - # - SERVICE=tic-tac-toe - # - EXTRA_FILES=tic-tac-toe/extra - # container_name: tic-tac-toe - # restart: unless-stopped - # networks: - # - transcendance-network - # volumes: - # - sqlite-volume:/volumes/database - # - static-volume:/volumes/static - # environment: - # - JWT_SECRET=KRUGKIDROVUWG2ZAMJZG653OEBTG66BANJ2W24DTEBXXMZLSEB2GQZJANRQXU6JA - # - DATABASE_DIR=/volumes/database - - ############### - # CHAT # - ############### chat: build: context: ./src/ args: - SERVICE=chat - - EXTRA_FILES=chat/extra - container_name: chat + container_name: app-chat restart: always networks: - - transcendance-network + - app volumes: - sqlite-volume:/volumes/database - static-volume:/volumes/static @@ -114,20 +84,21 @@ services: - DATABASE_DIR=/volumes/database - PROVIDER_FILE=/extra/providers.toml - SESSION_MANAGER=${SESSION_MANAGER} + logging: + driver: gelf + options: + gelf-address: "udp://127.0.0.1:12201" + tag: "{{.Name}}" - ############### - # USER # - ############### user: build: context: ./src/ args: - SERVICE=user - # - EXTRA_FILES=user/extra - container_name: user + container_name: app-user restart: always networks: - - transcendance-network + - app volumes: - sqlite-volume:/volumes/database - static-volume:/volumes/static @@ -146,16 +117,14 @@ services: ############### grafana: - container_name: monitoring-grafana + container_name: mon-grafana image: grafana/grafana-enterprise restart: always networks: - - transcendance-network + - app - monitoring depends_on: - prometheus - ports: - - '3000:3000' volumes: - ./monitoring/grafana/alerting:/etc/grafana/provisioning/alerting - ./monitoring/grafana/datasources:/etc/grafana/provisioning/datasources @@ -166,7 +135,7 @@ services: # this can stay the same for developpement. This is an alias to `localhost` - NGINX_DOMAIN=local.maix.me - GF_LOG_LEVEL=warn - - GF_SERVER_ROOT_URL=http://local.maix.me:3000 + - GF_SERVER_ROOT_URL=https://local.maix.me:9090/grafana/ - GF_SECURITY_ADMIN_USER=${GRAFANA_ADMIN_USER} - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASS} logging: @@ -174,12 +143,18 @@ services: options: gelf-address: "udp://127.0.0.1:12201" tag: "{{.Name}}" + healthcheck: + test: ["CMD-SHELL", "curl -f -s http://localhost:3000/api/health || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s prometheus: image: prom/prometheus:latest - container_name: monitoring-prometheus + container_name: mon-prometheus networks: - - transcendance-network + - app - monitoring volumes: - ./monitoring/prometheus:/etc/prometheus/ @@ -189,14 +164,22 @@ services: options: gelf-address: "udp://127.0.0.1:12201" tag: "{{.Name}}" + healthcheck: + test: ["CMD", "wget", "--quiet", "--spider", "http://localhost:9090/-/healthy"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 30s cadvisor: image: gcr.io/cadvisor/cadvisor:latest networks: - monitoring - container_name: monitoring-cadvisor - ports: - - '8080:8080' + container_name: mon-cadvisor + command: + - '-url_base_prefix=/cadvisor' + environment: + - CADVISOR_HEALTHCHECK_URL=http://localhost:8080/cadvisor/healthz volumes: - /:/rootfs:ro - /var/run:/var/run:ro @@ -209,20 +192,23 @@ services: gelf-address: "udp://127.0.0.1:12201" tag: "{{.Name}}" - blackbox: image: prom/blackbox-exporter:latest - container_name: monitoring-blackbox + container_name: mon-blackbox networks: - - transcendance-network - ports: - - "9115:9115" + - app restart: unless-stopped logging: driver: gelf options: gelf-address: "udp://127.0.0.1:12201" tag: "{{.Name}}" + healthcheck: + test: ["CMD", "wget", "--quiet", "--spider", "http://localhost:9115/-/healthy"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s @@ -232,7 +218,7 @@ services: elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:7.17.23 - container_name: logs-elasticsearch + container_name: log-elasticsearch networks: - monitoring environment: @@ -242,14 +228,18 @@ services: volumes: - elastic-data:/usr/share/elasticsearch/data - ./logs/elasticsearch:/setup - ports: - - "9200:9200" command: ["/setup/bootstrap.sh"] restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "-s", "localhost:9200"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s logstash: image: docker.elastic.co/logstash/logstash:7.17.23 - container_name: logs-logstash + container_name: log-logstash depends_on: - elasticsearch networks: @@ -259,25 +249,38 @@ services: ports: - "12201:12201/udp" restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "-s", "localhost:9600"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s kibana: image: docker.elastic.co/kibana/kibana:7.17.23 - container_name: logs-kibana + container_name: log-kibana depends_on: - elasticsearch networks: - monitoring + - app environment: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 - - SERVER_PUBLICBASEURL=http://local.maix.me:5601 + - SERVER_PUBLICBASEURL=https://local.maix.me:9090/kibana + - SERVER_BASEPATH=/kibana + - SERVER_REWRITEBASEPATH=true - ELASTICSEARCH_USERNAME=elastic - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} - ports: - - "5601:5601" volumes: - ./logs/kibana:/setup command: ["/setup/bootstrap.sh"] restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "-s", "localhost:5601/kibana/api/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s volumes: sqlite-volume: diff --git a/logs/kibana/bootstrap.sh b/logs/kibana/bootstrap.sh index c9235d1..a5a98d0 100755 --- a/logs/kibana/bootstrap.sh +++ b/logs/kibana/bootstrap.sh @@ -2,11 +2,11 @@ kibana_setup() { set -xe - until curl -s -f "localhost:5601/api/status"; do + until curl -s -f "localhost:5601/kibana/api/status"; do sleep 2 done - curl -v -X POST "localhost:5601/api/saved_objects/_import?overwrite=true" \ + curl -v -X POST "localhost:5601/kibana/api/saved_objects/_import?overwrite=true" \ -H "kbn-xsrf: true" \ --form file='@/setup/export.ndjson' exit 0 diff --git a/monitoring/prometheus/prometheus.yml b/monitoring/prometheus/prometheus.yml index c0027f9..7452f1b 100644 --- a/monitoring/prometheus/prometheus.yml +++ b/monitoring/prometheus/prometheus.yml @@ -17,10 +17,10 @@ scrape_configs: static_configs: - targets: - - http://nginx/monitoring/ok + - http://nginx:8080/ok - http://auth/monitoring - http://user/monitoring - - http://icons/monitoring + - http://chat/monitoring relabel_configs: - source_labels: [__address__] diff --git a/nginx/Dockerfile b/nginx/Dockerfile index 9d384f9..b152c1c 100644 --- a/nginx/Dockerfile +++ b/nginx/Dockerfile @@ -27,3 +27,9 @@ COPY ./15-local-resolvers.envsh /docker-entrypoint.d/ COPY ./17-add-template-prefix.sh /docker-entrypoint.d/ COPY ./conf /etc/nginx/templates +COPY ./monitoring.index.html /var/share/www/monitoring/ + +RUN chmod -R +r /var/share/www/monitoring/; + +HEALTHCHECK --interval=30s --timeout=3s \ + CMD curl -f -s http://localhost:8080/ok?docker || exit 1; \ No newline at end of file diff --git a/nginx/conf/default.conf b/nginx/conf/default.conf index e5892ac..c669e21 100644 --- a/nginx/conf/default.conf +++ b/nginx/conf/default.conf @@ -1,10 +1,15 @@ # please make sure you want to edit this file... +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + # this allows the redirection of `http://domain/URL` to `https://domain/URL` server { charset UTF-8; listen 80; - listen [::]:80; + #listen [::]:80; resolver $NGINX_RESOLVERS; server_name $NGINX_DOMAIN; @@ -14,16 +19,18 @@ server { server { charset UTF-8; - listen [::]:443 ssl; + #listen [::]:443 ssl; listen 443 ssl; resolver $NGINX_RESOLVERS; server_name $NGINX_DOMAIN; - ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt; + ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt; ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key; - ssl_protocols TLSv1.3; - + ssl_protocols TLSv1.3; + proxy_set_header X-Forwarded true; - error_page 497 https://$http_host$request_uri; + error_page 497 https://$http_host$request_uri; include conf.d/locations/*.conf; } + +include conf.d/monitoring/server.conf; \ No newline at end of file diff --git a/nginx/conf/locations/monitoring.conf b/nginx/conf/locations/monitoring.conf deleted file mode 100644 index 69e6e15..0000000 --- a/nginx/conf/locations/monitoring.conf +++ /dev/null @@ -1,4 +0,0 @@ -location /monitoring/ok { - add_header Content-Type text/plain; - return 200 'healthy'; -} diff --git a/nginx/conf/monitoring/locations.conf b/nginx/conf/monitoring/locations.conf new file mode 100644 index 0000000..da08a18 --- /dev/null +++ b/nginx/conf/monitoring/locations.conf @@ -0,0 +1,39 @@ +# This is required to proxy Grafana Live WebSocket connections. +location /kibana { + proxy_set_header Host $host; + set $upstream_kibana kibana:5601; + proxy_pass http://$upstream_kibana; +} + +location /cadvisor { + proxy_set_header Host $host; + set $upstream_cadvisor cadvisor:8080; + proxy_pass http://$upstream_cadvisor; +} + +location /grafana { + proxy_set_header Host $host; + rewrite ^/grafana/?(.*) /$1 break; + set $upstream_grafana grafana:3000; + proxy_pass http://$upstream_grafana; +} +# Proxy Grafana Live WebSocket connections. +location /grafana/api/live/ { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Host $host; + rewrite ^/grafana/?(.*) /$1 break; + set $upstream_grafana grafana:3000; + proxy_pass http://$upstream_grafana; +} + +location /ok { + add_header Content-Type text/plain; + return 200 'healthy'; +} + +location / { + root /var/share/www/monitoring/; + index monitoring.index.html; +} \ No newline at end of file diff --git a/nginx/conf/monitoring/server.conf b/nginx/conf/monitoring/server.conf new file mode 100644 index 0000000..fb1234d --- /dev/null +++ b/nginx/conf/monitoring/server.conf @@ -0,0 +1,26 @@ +server { + charset UTF-8; + listen 8080; + #listen [::]:8080; + resolver $NGINX_RESOLVERS; + server_name $NGINX_DOMAIN; + + include conf.d/monitoring/locations.conf; +} + + +server { + charset UTF-8; + #listen [::]:10443 ssl; + listen 8443 ssl; + resolver $NGINX_RESOLVERS; + server_name $NGINX_DOMAIN; + + ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt; + ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key; + ssl_protocols TLSv1.3; + + error_page 497 https://$http_host$request_uri; + + include conf.d/monitoring/locations.conf; +} \ No newline at end of file diff --git a/nginx/monitoring.index.html b/nginx/monitoring.index.html new file mode 100644 index 0000000..a400dca --- /dev/null +++ b/nginx/monitoring.index.html @@ -0,0 +1,64 @@ + + + + + Service Dashboard + + + +
+

Services

+ +
+ + \ No newline at end of file diff --git a/src/@shared/src/database/index.ts b/src/@shared/src/database/index.ts index ea111db..48e869a 100644 --- a/src/@shared/src/database/index.ts +++ b/src/@shared/src/database/index.ts @@ -28,8 +28,10 @@ export const useDatabase = fp(async function( if (dbAdded) { return; } dbAdded = true; const path = process.env.DATABASE_DIR; - if (isNullish(path)) { throw 'env `DATABASE_DIR` not defined'; } - f.log.info(`Opening database with path: ${path}/database.db`); + if (isNullish(path)) { + f.log.fatal('env `DATABASE_DIR` not defined'); + throw 'env `DATABASE_DIR` not defined'; + } const db: Database = new DbImpl(`${path}/database.db`) as Database; if (!f.hasDecorator('db')) { f.decorate('db', db); } }); diff --git a/src/@shared/src/utils/index.ts b/src/@shared/src/utils/index.ts index a79cbe9..745bbfc 100644 --- a/src/@shared/src/utils/index.ts +++ b/src/@shared/src/utils/index.ts @@ -11,7 +11,7 @@ import { FastifyReply } from 'fastify'; import fp from 'fastify-plugin'; export const useMonitoring = fp(async (fastify) => { - fastify.get('/monitoring', { schema: { hide: true } }, (req, res) => { + fastify.get('/monitoring', { schema: { hide: true }, logLevel: 'silent' }, (req, res) => { void req; res.code(200).send('Ok'); }); diff --git a/src/Dockerfile b/src/Dockerfile index 9f47b4e..6b7d366 100644 --- a/src/Dockerfile +++ b/src/Dockerfile @@ -1,6 +1,7 @@ FROM node:22-alpine AS pnpm_base RUN npm install --global pnpm@10 --no-fund -q; RUN apk add make python3 gcc clang build-base musl-dev; +RUN apk add --no-cache curl FROM pnpm_base AS deps WORKDIR /build @@ -50,5 +51,8 @@ COPY --from=deps /build/node_modules /src/node_modules COPY ${EXTRA_FILES} /extra ENTRYPOINT [ "/src/entrypoint.sh" ] +HEALTHCHECK --interval=30s --timeout=3s \ + CMD curl -f -s http://localhost/monitoring?docker || exit 1 + CMD ["node", "/src/run.cjs"] diff --git a/src/auth/entrypoint.sh b/src/auth/entrypoint.sh index a5c6509..f1735d5 100644 --- a/src/auth/entrypoint.sh +++ b/src/auth/entrypoint.sh @@ -1,12 +1,7 @@ #!/bin/sh set -e -set -x # do anything here -mkdir -p /volumes/static/auth/ -cp -r /extra/login_demo.html /volumes/static/auth/index.html -cp -r /extra/login_demo.js /volumes/static/auth/login_demo.js - # run the CMD [ ... ] from the dockerfile exec "$@" diff --git a/src/auth/src/run.ts b/src/auth/src/run.ts index d3d410f..3c59d5d 100644 --- a/src/auth/src/run.ts +++ b/src/auth/src/run.ts @@ -4,23 +4,9 @@ import fastify, { FastifyInstance } from 'fastify'; import app from './app'; const start = async () => { - const envToLogger = { - development: { - transport: { - target: 'pino-pretty', - options: { - translateTime: 'HH:MM:ss Z', - ignore: 'pid,hostname', - }, - }, - }, - production: true, - test: false, - }; - - const f: FastifyInstance = fastify({ logger: envToLogger.development }); + const f: FastifyInstance = fastify({ logger: { level: 'info' } }); process.on('SIGTERM', () => { - f.log.info('Requested to shutdown'); + f.log.warn('Requested to shutdown'); process.exit(134); }); try { diff --git a/src/chat/entrypoint.sh b/src/chat/entrypoint.sh index 2dcab02..f1735d5 100644 --- a/src/chat/entrypoint.sh +++ b/src/chat/entrypoint.sh @@ -1,7 +1,6 @@ #!/bin/sh set -e -set -x # do anything here # run the CMD [ ... ] from the dockerfile diff --git a/src/chat/src/run.ts b/src/chat/src/run.ts index d9f1e2a..3c59d5d 100644 --- a/src/chat/src/run.ts +++ b/src/chat/src/run.ts @@ -4,33 +4,18 @@ import fastify, { FastifyInstance } from 'fastify'; import app from './app'; const start = async () => { - const envToLogger = { - development: { - transport: { - target: 'pino-pretty', - options: { - translateTime: 'HH:MM:ss Z', - ignore: 'pid,hostname', - }, - }, - }, - production: true, - test: false, - }; - - const f: FastifyInstance = fastify({ logger: envToLogger.development }); + const f: FastifyInstance = fastify({ logger: { level: 'info' } }); + process.on('SIGTERM', () => { + f.log.warn('Requested to shutdown'); + process.exit(134); + }); try { - process.on('SIGTERM', () => { - f.log.info('Requested to shutdown'); - process.exit(134); - }); - console.log('-------->Serving static files from:'); await f.register(app, {}); await f.listen({ port: 80, host: '0.0.0.0' }); } catch (err) { f.log.error(err); process.exit(1); - }; + } }; -start(); \ No newline at end of file +start(); diff --git a/src/user/entrypoint.sh b/src/user/entrypoint.sh index 2dcab02..f1735d5 100644 --- a/src/user/entrypoint.sh +++ b/src/user/entrypoint.sh @@ -1,7 +1,6 @@ #!/bin/sh set -e -set -x # do anything here # run the CMD [ ... ] from the dockerfile diff --git a/src/user/src/run.ts b/src/user/src/run.ts index d3d410f..3c59d5d 100644 --- a/src/user/src/run.ts +++ b/src/user/src/run.ts @@ -4,23 +4,9 @@ import fastify, { FastifyInstance } from 'fastify'; import app from './app'; const start = async () => { - const envToLogger = { - development: { - transport: { - target: 'pino-pretty', - options: { - translateTime: 'HH:MM:ss Z', - ignore: 'pid,hostname', - }, - }, - }, - production: true, - test: false, - }; - - const f: FastifyInstance = fastify({ logger: envToLogger.development }); + const f: FastifyInstance = fastify({ logger: { level: 'info' } }); process.on('SIGTERM', () => { - f.log.info('Requested to shutdown'); + f.log.warn('Requested to shutdown'); process.exit(134); }); try {