PhotoFlow Documentation Help

Kubernetes Deployment

PhotoFlow runs on on-premise Kubernetes clusters with Helm-based deployments.

Cluster Architecture

Persistent Storage

Kubernetes Namespaces

Ingress Layer

photoflow

pfl-be-api

pfl-fe-web

photoflow-uat

pfl-be-api

pfl-fe-web

photoflow-dev

pfl-be-api

pfl-fe-web

pfl-mock

NGINX Ingress Controller

PostgreSQL

Redis Cache

Namespace Organization

Namespace

Purpose

URL Pattern

photoflow-dev

Development

dev.*.photoflow.vn

photoflow-uat

User Acceptance Testing

uat.*.photoflow.vn

photoflow-beta

Beta releases

beta.*.photoflow.vn

photoflow

Production

*.photoflow.vn

Helm # chart: helm/shin-service

PhotoFlow uses the shin-service Helm chart for consistent deployments.

Chart Information

Property

Value

Chart Name

shin-service

Version

0.3.2

Registry

oci://registry.gitlab.com/nextera-devops/nera-helm-chart/helm/shin-service

Supported Components

Component

Description

Port

api

REST API (.NET)

8080

grpc

gRPC service

8081

nextjs

Next.js frontend

3000

angular

Angular frontend

80

background

Background worker

-

Values Configuration

Base Values Structure

# values.yaml replicaCount: 1 image: repository: registry.shiningtree.co pullPolicy: IfNotPresent tag: "latest" name: "" # Full image name (e.g., photo-flow/backend/api) suffix: "" # Optional suffix for release name service: type: ClusterIP port: 80 targetPort: 8080 resources: limits: cpu: 500m memory: 512Mi requests: cpu: 250m memory: 256Mi probes: liveness: enabled: true initialDelaySeconds: 30 path: /health port: http readiness: enabled: true initialDelaySeconds: 5 path: /health port: http

Environment-Specific Values

Development (dev.yaml)

# devops/IaC/environments/dev.yaml replicaCount: 1 image: tag: dev resources: limits: cpu: 500m memory: 512Mi requests: cpu: 100m memory: 256Mi ingress: enabled: true className: nginx annotations: cert-manager.io/cluster-issuer: letsencrypt-prod hosts: - host: dev.api.photoflow.vn paths: - path: / pathType: Prefix tls: - secretName: dev-api-tls hosts: - dev.api.photoflow.vn configMap: enabled: true global: ASPNETCORE_ENVIRONMENT: Development LOG_LEVEL: Debug

Production (prod.yaml)

# devops/IaC/environments/prod.yaml replicaCount: 3 image: tag: latest resources: limits: cpu: 1000m memory: 1Gi requests: cpu: 500m memory: 512Mi autoscaling: enabled: true minReplicas: 2 maxReplicas: 10 targetCPUUtilizationPercentage: 70 ingress: enabled: true className: nginx annotations: cert-manager.io/cluster-issuer: letsencrypt-prod nginx.ingress.kubernetes.io/rate-limit: "100" hosts: - host: api.photoflow.vn paths: - path: / pathType: Prefix tls: - secretName: api-tls hosts: - api.photoflow.vn configMap: enabled: true global: ASPNETCORE_ENVIRONMENT: Production LOG_LEVEL: Warning

IaC Directory Structure

devops/IaC/ ├── _global.yaml # Shared settings ├── _ingress.yaml # Ingress templates ├── _containers/ │ ├── api.yaml # API container config │ ├── angular.yaml # Angular container config │ └── background.yaml # Worker container config └── environments/ ├── dev.yaml # Development overrides ├── uat.yaml # UAT overrides └── prod.yaml # Production settings

Container Configuration

# devops/IaC/_containers/api.yaml image: name: photo-flow/backend/pfl01y25-be-app suffix: "" service: port: 80 targetPort: 8080 configMap: components: api: ASPNETCORE_URLS: "http://+:8080" SERVICE_TYPE: api

Deployment Commands

Manual Deployment

# Deploy to development helm upgrade --install pfl-be-api \ oci://registry.gitlab.com/nextera-devops/nera-helm-chart/helm/shin-service \ --version 0.3.2 \ -n photoflow-dev \ -f devops/IaC/_global.yaml \ -f devops/IaC/_ingress.yaml \ -f devops/IaC/_containers/api.yaml \ -f devops/IaC/environments/dev.yaml \ --set image.tag=dev # Verify deployment kubectl get pods -n photoflow-dev -l app=pfl-be-api

Helm Operations

# List releases helm list -n photoflow-dev # Get release values helm get values pfl-be-api -n photoflow-dev # View release history helm history pfl-be-api -n photoflow-dev # Rollback to previous helm rollback pfl-be-api -n photoflow-dev

Ingress Configuration

NGINX Ingress Controller

# Ingress annotations ingress: annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: letsencrypt-prod nginx.ingress.kubernetes.io/proxy-body-size: "100m" nginx.ingress.kubernetes.io/proxy-read-timeout: "300" nginx.ingress.kubernetes.io/websocket-services: "pfl-be-api"

SignalR/WebSocket Support

# For SignalR connections nginx.ingress.kubernetes.io/websocket-services: "pfl-be-api" nginx.ingress.kubernetes.io/upstream-hash-by: "$remote_addr" nginx.ingress.kubernetes.io/affinity: "cookie" nginx.ingress.kubernetes.io/session-cookie-name: "route"

SSL/TLS with cert-manager

tls: - secretName: api-photoflow-tls hosts: - api.photoflow.vn

Resource Management

Default Resources

Component

CPU Request

CPU Limit

Memory Request

Memory Limit

API

250m

500m

256Mi

512Mi

Worker

100m

250m

128Mi

256Mi

Frontend

50m

100m

64Mi

128Mi

Production Resources

Component

CPU Request

CPU Limit

Memory Request

Memory Limit

API

500m

1000m

512Mi

1Gi

Worker

250m

500m

256Mi

512Mi

Frontend

100m

200m

128Mi

256Mi

Health Checks

Liveness Probe

Determines if container should be restarted:

probes: liveness: enabled: true initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 6 path: /health port: http

Readiness Probe

Determines if container can receive traffic:

probes: readiness: enabled: true initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 path: /health port: http

ConfigMaps and Secrets

ConfigMap Structure

configMap: enabled: true global: ASPNETCORE_ENVIRONMENT: Production LOG_LEVEL: Warning DB_HOST: postgres.photoflow.svc.cluster.local DB_PORT: "5432" components: api: ASPNETCORE_URLS: "http://+:8080" SignalR__Enabled: "true"

Secrets Management

# Create secret kubectl create secret generic pfl-secrets \ -n photoflow \ --from-literal=DB_PASSWORD='secure-password' \ --from-literal=JWT_SECRET='jwt-secret-key' # Reference in deployment envFrom: - secretRef: name: pfl-secrets

Autoscaling

Horizontal Pod Autoscaler

autoscaling: enabled: true minReplicas: 2 maxReplicas: 10 targetCPUUtilizationPercentage: 70 targetMemoryUtilizationPercentage: 80

Verify HPA

kubectl get hpa -n photoflow kubectl describe hpa pfl-be-api -n photoflow

Monitoring

Service Monitor (Prometheus)

serviceMonitor: enabled: true interval: 30s scrapeTimeout: 10s additionalLabels: release: prometheus

Pod Metrics

# View pod resource usage kubectl top pods -n photoflow # View pod logs kubectl logs -f deployment/pfl-be-api -n photoflow # Stream all replica logs kubectl logs -f -l app=pfl-be-api -n photoflow --all-containers

Troubleshooting

Common Issues

Issue

Diagnosis

Solution

Pod CrashLoopBackOff

Check logs

Fix application errors

ImagePullBackOff

Registry auth

Verify imagePullSecrets

Pending pods

Resource constraints

Check node resources

502 Bad Gateway

Pod not ready

Check readiness probe

Debug Commands

# Describe pod kubectl describe pod <pod-name> -n photoflow # Get events kubectl get events -n photoflow --sort-by='.lastTimestamp' # Exec into pod kubectl exec -it <pod-name> -n photoflow -- /bin/sh # Port forward for local debugging kubectl port-forward svc/pfl-be-api 8080:80 -n photoflow
Last modified: 25 February 2026