apiVersion: v1 kind: Pod metadata: name: sharenet-production-pod labels: app: sharenet-production annotations: io.containers.no-new-privileges: "true" spec: hostname: sharenet-production-pod # Security: run as non-root user with specific UID/GID (matches PROD_SERVICE_USER) securityContext: runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 fsGroup: 1000 containers: - name: postgres image: ${REGISTRY_HOST}/${APP_NAME}/postgres:${IMAGE_TAG} # Security: drop all capabilities, read-only root filesystem except data volume securityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: ["ALL"] env: - name: POSTGRES_DB value: ${POSTGRES_DATABASE_NAME} - name: POSTGRES_USER value: ${POSTGRES_USERNAME} - name: PGDATA value: /var/lib/postgresql/data/pgdata ports: - containerPort: ${POSTGRES_PORT} protocol: TCP volumeMounts: - name: pgdata mountPath: /var/lib/postgresql/data readOnly: false # Health checks livenessProbe: exec: command: ["pg_isready", "-U", "sharenet"] initialDelaySeconds: 30 periodSeconds: 30 timeoutSeconds: 10 failureThreshold: 3 readinessProbe: exec: command: ["pg_isready", "-U", "sharenet"] initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 5 # Resource limits resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "1Gi" cpu: "500m" - name: backend image: ${REGISTRY_HOST}/${APP_NAME}/backend:${IMAGE_TAG} # Security: drop all capabilities, read-only root filesystem securityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: ["ALL"] env: - name: DATABASE_URL value: postgres://${POSTGRES_USERNAME}:${POSTGRES_PASSWORD}@{POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DATABASE_NAME}?sslmode=disable - name: PORT value: ${PROD_BACKEND_PORT} ports: - containerPort: ${PROD_BACKEND_PORT} protocol: TCP # Health checks livenessProbe: httpGet: path: /health port: ${PROD_BACKEND_PORT} scheme: HTTP initialDelaySeconds: 30 periodSeconds: 30 timeoutSeconds: 10 failureThreshold: 3 readinessProbe: httpGet: path: /health port: ${PROD_BACKEND_PORT} scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 5 # Resource limits resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "512Mi" cpu: "250m" - name: frontend image: ${REGISTRY_HOST}/${APP_NAME}/frontend:${IMAGE_TAG} # Security: drop all capabilities, read-only root filesystem securityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: ["ALL"] env: - name: NEXT_PUBLIC_API_HOST value: ${PROD_BACKEND_HOST} - name: NEXT_PUBLIC_API_PORT value: ${PROD_BACKEND_PORT} - name: PORT value: ${PROD_FRONTEND_PORT} ports: - containerPort: ${PROD_FRONTEND_PORT} protocol: TCP # Resource limits resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "250m" - name: nginx image: ${REGISTRY_HOST}/${APP_NAME}/nginx:${IMAGE_TAG} # Security: drop all capabilities, read-only root filesystem securityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: ["ALL"] ports: - containerPort: 80 protocol: TCP - containerPort: 443 protocol: TCP volumeMounts: - name: nginx-conf mountPath: /etc/nginx/nginx.conf subPath: nginx.conf readOnly: true - name: nginx-cache mountPath: /var/cache/nginx readOnly: false - name: letsencrypt mountPath: /etc/letsencrypt readOnly: true # Health check livenessProbe: httpGet: path: /healthz port: 80 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 30 timeoutSeconds: 5 failureThreshold: 3 # Resource limits resources: requests: memory: "64Mi" cpu: "50m" limits: memory: "128Mi" cpu: "100m" volumes: - name: pgdata hostPath: path: /opt/sharenet/volumes/pgdata type: DirectoryOrCreate - name: nginx-conf hostPath: path: /opt/sharenet/nginx type: Directory - name: nginx-cache hostPath: path: /opt/sharenet/volumes/nginx-cache type: DirectoryOrCreate - name: letsencrypt hostPath: path: /etc/letsencrypt type: Directory