Add base kubernetes support 2
This commit is contained in:
@@ -1,38 +0,0 @@
|
||||
# frontend/Dockerfile.development - FIXED VERSION
|
||||
FROM node:18-alpine
|
||||
|
||||
# Install curl for healthchecks
|
||||
RUN apk add --no-cache curl
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Create non-root user for security but don't switch yet
|
||||
RUN addgroup -g 1001 -S nodejs && \
|
||||
adduser -S reactjs -u 1001 -G nodejs
|
||||
|
||||
# Copy package files first (better caching)
|
||||
COPY package*.json ./
|
||||
|
||||
# Install all dependencies (including dev dependencies) as root
|
||||
RUN npm ci --verbose && \
|
||||
npm cache clean --force
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Change ownership of all files to the non-root user
|
||||
RUN chown -R reactjs:nodejs /app
|
||||
|
||||
# Now switch to non-root user
|
||||
USER reactjs
|
||||
|
||||
# Expose port 3000 (Vite default)
|
||||
EXPOSE 3000
|
||||
|
||||
# Add healthcheck
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
||||
CMD curl -f http://localhost:3000/ || exit 1
|
||||
|
||||
# Start development server with host binding
|
||||
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
|
||||
@@ -1,5 +1,5 @@
|
||||
# Production Dockerfile for Frontend with Nginx
|
||||
# Multi-stage build for optimal size and performance
|
||||
# Kubernetes-optimized Dockerfile for Frontend
|
||||
# Multi-stage build for production deployment
|
||||
|
||||
# Stage 1: Build the application
|
||||
FROM node:18-alpine AS builder
|
||||
@@ -17,6 +17,7 @@ RUN npm ci --verbose && \
|
||||
COPY . .
|
||||
|
||||
# Build the application for production
|
||||
# This will use environment variables available at build time
|
||||
RUN npm run build
|
||||
|
||||
# Stage 2: Production server with Nginx
|
||||
@@ -34,7 +35,30 @@ COPY nginx.conf /etc/nginx/conf.d/
|
||||
# Copy built application from builder stage
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
# Nginx user already exists in the base image, just ensure proper ownership
|
||||
# Create a script to substitute environment variables at runtime
|
||||
COPY <<'EOF' /docker-entrypoint.d/30-substitute-env.sh
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# Default values for environment variables
|
||||
export VITE_API_URL=${VITE_API_URL:-"http://gateway-service:8000"}
|
||||
export VITE_APP_TITLE=${VITE_APP_TITLE:-"PanIA Dashboard"}
|
||||
export VITE_APP_VERSION=${VITE_APP_VERSION:-"1.0.0"}
|
||||
|
||||
# Create a runtime configuration file that can be loaded by the frontend
|
||||
cat > /usr/share/nginx/html/runtime-config.js << EOL
|
||||
window.__RUNTIME_CONFIG__ = {
|
||||
VITE_API_URL: '${VITE_API_URL}',
|
||||
VITE_APP_TITLE: '${VITE_APP_TITLE}',
|
||||
VITE_APP_VERSION: '${VITE_APP_VERSION}'
|
||||
};
|
||||
EOL
|
||||
|
||||
echo "Runtime configuration created with API URL: ${VITE_API_URL}"
|
||||
EOF
|
||||
|
||||
# Make the script executable
|
||||
RUN chmod +x /docker-entrypoint.d/30-substitute-env.sh
|
||||
|
||||
# Set proper permissions
|
||||
RUN chown -R nginx:nginx /usr/share/nginx/html && \
|
||||
@@ -65,7 +89,7 @@ EXPOSE 3000
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
||||
CMD curl -f http://localhost:3000/ || exit 1
|
||||
CMD curl -f http://localhost:3000/health || exit 1
|
||||
|
||||
# Start nginx
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -1,41 +0,0 @@
|
||||
# frontend/Dockerfile.production
|
||||
# Multi-stage build for production
|
||||
|
||||
# Build stage
|
||||
FROM node:18-alpine as builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
|
||||
# Install dependencies
|
||||
RUN npm ci --only=production
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Build the application
|
||||
RUN npm run build
|
||||
|
||||
# Production stage
|
||||
FROM nginx:alpine
|
||||
|
||||
# Install curl for healthchecks
|
||||
RUN apk add --no-cache curl
|
||||
|
||||
# Copy built app from builder stage
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
# Copy nginx configuration
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
# Expose port 80
|
||||
EXPOSE 80
|
||||
|
||||
# Add healthcheck
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
|
||||
CMD curl -f http://localhost/ || exit 1
|
||||
|
||||
# Start nginx
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -22,6 +22,8 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<!-- Runtime configuration - loaded by Kubernetes deployment -->
|
||||
<script src="/runtime-config.js"></script>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -12,7 +12,7 @@ server {
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://fonts.googleapis.com https://js.stripe.com; script-src-elem 'self' 'unsafe-inline' https://js.stripe.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' http://localhost:8000 http://localhost:8006 ws: wss:; frame-src https://js.stripe.com;" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://fonts.googleapis.com https://js.stripe.com; script-src-elem 'self' 'unsafe-inline' https://js.stripe.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' http://gateway-service:8000 http://localhost:8000 http://localhost:8006 ws: wss:; frame-src https://js.stripe.com;" always;
|
||||
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
@@ -31,9 +31,9 @@ server {
|
||||
application/atom+xml
|
||||
image/svg+xml;
|
||||
|
||||
# API proxy to gateway service (Kubernetes internal name)
|
||||
# API proxy to gateway service (Kubernetes service name)
|
||||
location /api/ {
|
||||
proxy_pass http://gateway:8000;
|
||||
proxy_pass http://gateway-service:8000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
* React Query doesn't replace HTTP clients - it manages data fetching/caching/sync
|
||||
*/
|
||||
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
|
||||
import { getApiUrl } from '../../config/runtime';
|
||||
|
||||
export interface ApiError {
|
||||
message: string;
|
||||
@@ -55,7 +56,7 @@ class ApiClient {
|
||||
config: AxiosRequestConfig;
|
||||
}> = [];
|
||||
|
||||
constructor(baseURL: string = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000/api/v1') {
|
||||
constructor(baseURL: string = getApiUrl() + '/api/v1') {
|
||||
this.baseURL = baseURL;
|
||||
|
||||
this.client = axios.create({
|
||||
|
||||
62
frontend/src/config/runtime.ts
Normal file
62
frontend/src/config/runtime.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
// Runtime configuration for Kubernetes deployments
|
||||
// This allows environment variables to be injected at container startup
|
||||
|
||||
interface RuntimeConfig {
|
||||
VITE_API_URL: string;
|
||||
VITE_APP_TITLE: string;
|
||||
VITE_APP_VERSION: string;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__RUNTIME_CONFIG__?: RuntimeConfig;
|
||||
}
|
||||
}
|
||||
|
||||
// Types are defined in vite-env.d.ts
|
||||
|
||||
// Get configuration from runtime or fall back to build-time environment variables
|
||||
function getRuntimeConfig(): RuntimeConfig {
|
||||
// First try to get from window (injected at runtime in Kubernetes)
|
||||
if (typeof window !== 'undefined' && window.__RUNTIME_CONFIG__) {
|
||||
return window.__RUNTIME_CONFIG__;
|
||||
}
|
||||
|
||||
// Fall back to build-time environment variables (development/local)
|
||||
return {
|
||||
VITE_API_URL: import.meta.env.VITE_API_URL || 'http://localhost:8000',
|
||||
VITE_APP_TITLE: import.meta.env.VITE_APP_TITLE || 'PanIA Dashboard',
|
||||
VITE_APP_VERSION: import.meta.env.VITE_APP_VERSION || '1.0.0',
|
||||
};
|
||||
}
|
||||
|
||||
export const config = getRuntimeConfig();
|
||||
|
||||
// Helper function to get the API base URL
|
||||
export function getApiUrl(): string {
|
||||
return config.VITE_API_URL;
|
||||
}
|
||||
|
||||
// Helper function to get app title
|
||||
export function getAppTitle(): string {
|
||||
return config.VITE_APP_TITLE;
|
||||
}
|
||||
|
||||
// Helper function to get app version
|
||||
export function getAppVersion(): string {
|
||||
return config.VITE_APP_VERSION;
|
||||
}
|
||||
|
||||
// Helper to check if running in Kubernetes
|
||||
export function isKubernetesEnvironment(): boolean {
|
||||
return typeof window !== 'undefined' && !!window.__RUNTIME_CONFIG__;
|
||||
}
|
||||
|
||||
// Debug function to log current configuration
|
||||
export function logConfig(): void {
|
||||
console.log('Current configuration:', {
|
||||
...config,
|
||||
isKubernetes: isKubernetesEnvironment(),
|
||||
source: isKubernetesEnvironment() ? 'runtime' : 'build-time'
|
||||
});
|
||||
}
|
||||
14
frontend/src/vite-env.d.ts
vendored
Normal file
14
frontend/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_API_URL: string
|
||||
readonly VITE_API_BASE_URL: string
|
||||
readonly VITE_APP_TITLE: string
|
||||
readonly VITE_APP_VERSION: string
|
||||
readonly VITE_ENVIRONMENT: string
|
||||
// more env variables...
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv
|
||||
}
|
||||
@@ -28,10 +28,12 @@ export default defineConfig({
|
||||
},
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: process.env.NODE_ENV === 'development'
|
||||
? 'http://gateway:8000' // Use internal service name in Kubernetes
|
||||
: 'http://localhost:8000',
|
||||
target: process.env.VITE_API_URL ||
|
||||
(process.env.NODE_ENV === 'development' && process.env.KUBERNETES_SERVICE_HOST
|
||||
? 'http://gateway-service:8000' // Kubernetes internal service
|
||||
: 'http://localhost:8000'), // Local development
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, ''),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user