diff --git a/Dockerfile b/Dockerfile index b0026fe..d03dba4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,6 +38,7 @@ COPY --from=backend-builder /app/backend/package.json ./backend/ COPY --from=backend-builder /app/backend/node_modules ./backend/node_modules COPY --from=frontend-builder /app/frontend/build ./frontend/build -EXPOSE 3007 +ENV PORT=80 +EXPOSE 80 CMD ["/bin/sh", "-c", "cd /app/backend && node dist/server.js"] diff --git a/README.md b/README.md index dee4e99..4937265 100644 --- a/README.md +++ b/README.md @@ -83,12 +83,58 @@ docker pull xolvio/instant-mock: ### Kubernetes (K8s) -A basic Helm chart is provided to deploy InstantMock with Kubernetes. Currently, it ships with SQLite and is limited to a single replica. +A basic Helm chart is provided to deploy InstantMock with Kubernetes. Currently, +it ships with SQLite and is limited to a single replica. > 🔮 **Coming Soon**: Full Helm chart with scaling support and PostgreSQL. +## 🚢 Kubernetes Deployment with Istio + +### Basic Installation + +InstantMock is designed to work seamlessly with Istio service mesh. To deploy: + +1. Add the Helm repository +2. Create a values file with your domain configuration +3. Install using Helm + +The minimal configuration requires: + +- Your domain name +- Istio gateway configuration +- Backend URL (matching your domain) + +### Example Values File + +Create a `my-values.yaml` with your configuration: + +- Set ingress.hosts[0].host to your domain +- Set env.BACKEND_URL to match your domain +- Keep service.type as ClusterIP (Istio handles external access) +- Port 80 is used internally (Istio handles SSL/TLS) + +### Installation Command + +Run Helm install with your values: + + helm install instant-mock ./helm -f my-values.yaml + +### Accessing the Application + +Once deployed: + +1. Configure your Istio Gateway +2. Point your domain DNS to the Istio ingress gateway +3. Access InstantMock through your configured domain + +The application automatically detects the environment and configures itself for +production use. + +> Note: SSL/TLS termination is handled by Istio at the gateway level + ## 🙏 Acknowledgments -InstantMock builds on the work from gqmock, with many of the base MockServer utilities adapted and extended for seamless integration. +InstantMock builds on the work from gqmock, with many of the base MockServer +utilities adapted and extended for seamless integration. > Made with ❤️ by the @xolvio team diff --git a/backend/package-lock.json b/backend/package-lock.json index 14f9e7a..a3b7dce 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,12 +1,12 @@ { "name": "backend", - "version": "1.0.0-beta.4.3", + "version": "1.0.0-beta.4.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "backend", - "version": "1.0.0-beta.4.3", + "version": "1.0.0-beta.4.4", "dependencies": { "@apollo/client": "3.11.8", "@apollo/federation": "^0.38.1", diff --git a/backend/package.json b/backend/package.json index 8396425..832dbfb 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "backend", - "version": "1.0.0-beta.4.3", + "version": "1.0.0-beta.4.4", "main": "dist/server.js", "scripts": { "build": "rm -rf dist/ && npx tsc && npm run copy-graphql", diff --git a/backend/src/server.ts b/backend/src/server.ts index 5145c8e..a2d2d66 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -62,7 +62,7 @@ logger.startup('Checking APOLLO_API_KEY presence', { present: !!process.env.APOLLO_API_KEY, }); -const port = process.env.PORT || 3033; +const port = process.env.NODE_ENV === 'production' ? 80 : (process.env.PORT || 3033); export const DI = {} as { orm: MikroORM; @@ -177,15 +177,41 @@ const initializeApp = async () => { logger.api('Swagger API documentation served'); }); - app.use(express.static(path.join(__dirname, '../../frontend/build'))); - app.get('*', (_, res) => { - res.sendFile(path.join(__dirname, '../../frontend/build', 'index.html')); + app.get('*', (req, res, next) => { + if (req.path === '/') { + const indexPath = path.join(__dirname, '../../frontend/build', 'index.html'); + let html = fs.readFileSync(indexPath, 'utf8'); + + const backendUrl = process.env.BACKEND_URL || 'localhost'; + const port = process.env.NODE_ENV === 'production' + ? '' + : `:${process.env.PORT || '3033'}`; + + const runtimeConfig = { + BACKEND_URL: `http://${backendUrl}`, + BACKEND_PORT: port + }; + + html = html.replace( + '', + `` + ); + + return res.send(html); + } + next(); }); + app.use(express.static(path.join(__dirname, '../../frontend/build'))); + app.use(authMiddleware.error); app.listen(port, () => { - logger.startup('Server running', {port, url: `http://localhost:${port}`}); + logger.startup('Server running', { + port, + url: `http://localhost:${port}`, + env: process.env.NODE_ENV + }); }); }; diff --git a/frontend/src/config/config.ts b/frontend/src/config/config.ts index 5b21cf0..8283e14 100644 --- a/frontend/src/config/config.ts +++ b/frontend/src/config/config.ts @@ -1,7 +1,9 @@ export const config = { env: process.env.NODE_ENV as 'development' | 'production' | 'test', backend: { - url: `${process.env.REACT_APP_BACKEND_URL || 'http://localhost'}:${process.env.REACT_APP_BACKEND_PORT || '3033'}`, + url: typeof window !== 'undefined' && window.__RUNTIME_CONFIG__ + ? `${window.__RUNTIME_CONFIG__.BACKEND_URL}${window.__RUNTIME_CONFIG__.BACKEND_PORT ? `:${window.__RUNTIME_CONFIG__.BACKEND_PORT}` : ''}` + : `${process.env.REACT_APP_BACKEND_URL || 'http://localhost'}:${process.env.REACT_APP_BACKEND_PORT || '3033'}`, }, frontend: { url: `${process.env.REACT_APP_FRONTEND_URL || 'http://localhost'}:${process.env.REACT_APP_FRONTEND_PORT || '3032'}`, diff --git a/frontend/src/types/window.d.ts b/frontend/src/types/window.d.ts new file mode 100644 index 0000000..9237f07 --- /dev/null +++ b/frontend/src/types/window.d.ts @@ -0,0 +1,6 @@ +declare interface Window { + __RUNTIME_CONFIG__: { + BACKEND_URL: string; + BACKEND_PORT: string; + }; +} \ No newline at end of file diff --git a/helm/values.yaml b/helm/values.yaml index 3b3efb7..6a869e1 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -1,11 +1,28 @@ replicaCount: 1 image: repository: xolvio/instant-mock - tag: 1.0.0-beta.4.3 + tag: 1.0.0-beta.4.4 pullPolicy: Always service: - type: LoadBalancer + type: ClusterIP port: 80 +ingress: + enabled: true + className: istio + annotations: + kubernetes.io/ingress.class: istio + hosts: + - host: instant-mock.example.com + paths: + - path: / + pathType: Prefix +env: + - name: NODE_ENV + value: production + - name: BACKEND_URL + value: instant-mock.example.com + - name: PORT + value: '80' resources: {} persistence: enabled: true diff --git a/package-lock.json b/package-lock.json index b0e99a2..d9ff548 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "instant-mock", - "version": "1.0.0-beta.4.3", + "version": "1.0.0-beta.4.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "instant-mock", - "version": "1.0.0-beta.4.3", + "version": "1.0.0-beta.4.4", "license": "ISC", "devDependencies": { "@types/jest": "^29.5.14", diff --git a/package.json b/package.json index 7546b6b..cee094b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "instant-mock", - "version": "1.0.0-beta.4.3", + "version": "1.0.0-beta.4.4", "description": "![instant-mock-screen-cap-final](https://github.com/user-attachments/assets/de0f50d4-5a71-4e5a-b479-37c6cfa0481d)", "main": "index.js", "module": "true",