From 5c753478872c530f6c1aaac8d1600d2ba95c98b9 Mon Sep 17 00:00:00 2001 From: Gabriel Matte Date: Fri, 6 Dec 2024 21:01:23 -0500 Subject: [PATCH] Adds basic health checks --- client/Dockerfile | 3 +++ docker-compose.local.yaml | 25 +++++++++++++++++++------ nginx/Dockerfile | 4 ++++ nginx/templates/default.conf | 20 ++++++++++++++++++++ server/Dockerfile | 3 +++ server/app.js | 2 ++ server/routers/health.js | 20 ++++++++++++++++++++ 7 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 server/routers/health.js diff --git a/client/Dockerfile b/client/Dockerfile index f1021e6..de13cac 100644 --- a/client/Dockerfile +++ b/client/Dockerfile @@ -14,4 +14,7 @@ RUN npm run build EXPOSE 5173 +HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \ + CMD curl -f http://localhost:5173 || exit 1 + CMD [ "npm", "run", "preview" ] \ No newline at end of file diff --git a/docker-compose.local.yaml b/docker-compose.local.yaml index 541ac39..7f1fba5 100644 --- a/docker-compose.local.yaml +++ b/docker-compose.local.yaml @@ -12,7 +12,7 @@ services: networks: - quiz_network restart: always - + backend: build: context: ./server @@ -33,7 +33,8 @@ services: FRONTEND_URL: "http://localhost:5173" #QUIZROOM_IMAGE: ghcr.io/ets-cfuhrman-pfe/evaluetonsavoir-quizroom:latest depends_on: - - mongo + mongo: + condition: service_healthy networks: - quiz_network restart: always @@ -45,8 +46,6 @@ services: container_name: quizroom ports: - "4500:4500" - depends_on: - - backend networks: - quiz_network restart: always @@ -59,8 +58,10 @@ services: ports: - "80:80" depends_on: - - backend - - frontend + frontend: + condition: service_healthy + backend: + condition: service_healthy networks: - quiz_network restart: always @@ -70,6 +71,12 @@ services: # - FRONTEND_PORT=5173 # - BACKEND_HOST=backend # - BACKEND_PORT=3000 + healthcheck: + test: ["CMD-SHELL", "wget --spider http://0.0.0.0:${PORT}/health || exit 1"] + interval: 5s + timeout: 10s + start_period: 5s + retries: 6 mongo: image: mongo @@ -82,6 +89,12 @@ services: networks: - quiz_network restart: always + healthcheck: + test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"] + interval: 10s + timeout: 5s + retries: 3 + start_period: 20s watchtower: image: containrrr/watchtower diff --git a/nginx/Dockerfile b/nginx/Dockerfile index 37ffb53..3fc92ad 100644 --- a/nginx/Dockerfile +++ b/nginx/Dockerfile @@ -9,6 +9,7 @@ FROM alpine:3.19 # Install gettext for envsubst and other dependencies RUN apk add --no-cache \ gettext \ + curl \ nginx-mod-http-js \ nginx-mod-http-keyval \ pcre2 \ @@ -80,5 +81,8 @@ RUN chmod +x /entrypoint.sh && \ # Switch to nginx user USER nginx +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ + CMD wget -q --spider http://0.0.0.0:${PORT}/health || exit 1 + # Start Nginx using entrypoint script ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file diff --git a/nginx/templates/default.conf b/nginx/templates/default.conf index e732fc3..7fdff8d 100644 --- a/nginx/templates/default.conf +++ b/nginx/templates/default.conf @@ -19,6 +19,26 @@ server { listen ${PORT}; set $proxy_target ""; + + location /health { + access_log off; + add_header Content-Type text/plain; + return 200 'healthy'; + } + + location /backend-health { + proxy_pass http://backend/health; + proxy_http_version 1.1; + proxy_set_header Host $host; + access_log off; + } + + location /frontend-health { + proxy_pass http://frontend; + proxy_http_version 1.1; + proxy_set_header Host $host; + access_log off; + } location /api { proxy_pass http://backend; diff --git a/server/Dockerfile b/server/Dockerfile index 02bb17e..12713de 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -10,4 +10,7 @@ COPY ./ . EXPOSE 4400 +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:${PORT}/health || exit 1 + CMD ["npm", "run", "start"] \ No newline at end of file diff --git a/server/app.js b/server/app.js index afba445..3b4e7db 100644 --- a/server/app.js +++ b/server/app.js @@ -47,6 +47,7 @@ const folderRouter = require('./routers/folders.js'); const quizRouter = require('./routers/quiz.js'); const imagesRouter = require('./routers/images.js'); const roomRouter = require('./routers/rooms.js'); +const healthRouter = require('./routers/health.js'); // Setup environment dotenv.config(); @@ -71,6 +72,7 @@ app.use('/api/folder', folderRouter); app.use('/api/quiz', quizRouter); app.use('/api/image', imagesRouter); app.use('/api/room', roomRouter); +app.use('/health', healthRouter); app.use(errorHandler); diff --git a/server/routers/health.js b/server/routers/health.js new file mode 100644 index 0000000..008452e --- /dev/null +++ b/server/routers/health.js @@ -0,0 +1,20 @@ +const express = require('express'); +const router = express.Router(); + +router.get('/', async (req, res) => { + try { + const dbStatus = await require('../config/db.js').getConnection() ? 'connected' : 'disconnected'; + res.json({ + status: 'healthy', + timestamp: new Date(), + db: dbStatus + }); + } catch (error) { + res.status(500).json({ + status: 'unhealthy', + error: error.message + }); + } +}); + +module.exports = router; \ No newline at end of file