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 containers: - name: postgres image: ${REGISTRY_HOST}/${APP_NAME}/postgres:${IMAGE_TAG} # Security: drop all capabilities, read-only root filesystem except data volume securityContext: runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: ["ALL"] env: - name: POSTGRES_DB value: ${POSTGRES_DATABASE_NAME} - name: POSTGRES_USER value: ${POSTGRES_USERNAME} - name: POSTGRES_PASSWORD value: ${POSTGRES_PASSWORD} - name: PGDATA value: /var/lib/postgresql/data/pgdata ports: - containerPort: ${POSTGRES_PORT} protocol: TCP volumeMounts: - { name: pgdata, mountPath: /var/lib/postgresql/data, readOnly: false } - { name: postgres-run, mountPath: /var/run/postgresql, readOnly: false } # Health checks livenessProbe: exec: command: ["pg_isready", "-U", "${POSTGRES_USERNAME}"] initialDelaySeconds: 30 periodSeconds: 30 timeoutSeconds: 10 failureThreshold: 3 readinessProbe: exec: command: ["pg_isready", "-U", "${POSTGRES_USERNAME}"] 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: runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: ["ALL"] env: - name: DATABASE_URL value: "postgres://${POSTGRES_USERNAME}:${POSTGRES_PASSWORD}@localhost:${POSTGRES_PORT}/${POSTGRES_DATABASE_NAME}?sslmode=disable" - name: PORT value: "${PROD_BACKEND_PORT}" ports: - containerPort: ${PROD_BACKEND_PORT} protocol: TCP volumeMounts: - { name: backend-tmp, mountPath: /tmp } - { name: backend-tmp, mountPath: /run } # 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: runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 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 volumeMounts: - { name: frontend-tmp, mountPath: /tmp } - { name: frontend-tmp, mountPath: /run } # 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 hostPort: 8080 protocol: TCP - containerPort: 443 hostPort: 8443 protocol: TCP volumeMounts: - { name: nginx-run, mountPath: /var/run, readOnly: false } - { name: nginx-conf, mountPath: /etc/nginx/nginx.conf, readOnly: true, subPath: nginx.conf } - { name: nginx-cache, mountPath: /var/cache/nginx, readOnly: false } - { name: letsencrypt, mountPath: /etc/letsencrypt, readOnly: true } # Health check livenessProbe: httpGet: path: /healthz port: 8090 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: postgres-run emptyDir: {} - name: backend-tmp emptyDir: { medium: Memory } - name: frontend-tmp emptyDir: { medium: Memory } - name: nginx-run emptyDir: {} - 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