PhotoFlow Documentation Help

CI/CD Pipeline

PhotoFlow uses GitLab CI/CD with a modular template-based architecture for consistent deployments across all services.

Pipeline Architecture

Pipeline Stages

GitLab CI/CD

Target Environments

Development

UAT

Production

Service Pipelines

Backend .gitlab-ci.yml

Frontend .gitlab-ci.yml

Mock .gitlab-ci.yml

ci-templates Repository

dotnet-service.yml

helm-deploy.yml

docker-build.yml

Check/Lint

Build Docker

Deploy Helm

Template Structure

PhotoFlow CI/CD templates are organized in devops/ci-templates/:

ci-templates/ ├── config/ │ ├── docker.yml # Docker configuration │ ├── variables.yml # Global variables │ └── runners.yml # Runner configurations ├── jobs/ │ ├── docker-build.yml # Build jobs │ ├── helm-deploy.yml # Deployment jobs │ ├── mr-validation.yml # MR checks │ └── gitops-update.yml # GitOps updates ├── pipelines/ │ └── dotnet-service.yml # Complete .NET pipeline └── helm-templates/ # Helm value templates

Pipeline Stages

1. Check Stage

Runs on merge requests for code quality validation:

mr-check: extends: .mr_check_dotnet rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

Validates:

  • YAML syntax

  • Code formatting

  • Linting rules

  • Unit tests

2. Build Stage

Builds Docker images for each environment:

build-dev: extends: .docker_build_all variables: IMAGE_TAG: dev rules: - if: '$CI_COMMIT_REF_NAME == $DEV_BRANCH' build-uat: extends: .docker_build_all variables: IMAGE_TAG: uat rules: - if: '$CI_COMMIT_REF_NAME == $UAT_BRANCH' when: manual build-prod: extends: .docker_build_all variables: IMAGE_TAG: ${CI_COMMIT_TAG:-latest} rules: - if: '$CI_COMMIT_TAG' when: manual

3. Deploy Stage

Deploys to Kubernetes using Helm:

deploy-dev: extends: .helm_deploy_dev needs: [build-dev] rules: - if: '$ENABLE_DEV_DEPLOY == "true"' deploy-prod: extends: .helm_deploy_prod needs: [build-prod] rules: - if: '$ENABLE_PROD_DEPLOY == "true"' when: manual

Image Tag Convention

Environment

Branch

Tag

Development

develop

dev

Beta

develop

beta

UAT

uat

uat

Production

main/master

latest or git tag

Service Pipeline Configuration

Backend API Example

# pfl01y25-be-app/.gitlab-ci.yml include: - project: 'shining-tree/devops/ci-templates' ref: develop file: 'pipelines/dotnet-service.yml' - project: 'shining-tree/devops/ci-templates' ref: develop file: 'jobs/gitops-update.yml' default: tags: - pfl-docker variables: SERVICE_NAME: "pfl-be-api" HELM_RELEASE_NAME: "pfl-be-api" # Registry REGISTRY_URL: "registry.shiningtree.co" IMAGE_PATH: "photo-flow/backend/pfl01y25-be-app" # Components ENABLE_API_COMPONENT: "true" ENABLE_GRPC_COMPONENT: "false" # Helm Chart HELM_CHART_OCI: "oci://registry.gitlab.com/nextera-devops/nera-helm-chart/helm/shin-service" HELM_CHART_VERSION: "1.0.0" # Values files DEV_VALUES_FILE: "devops/IaC/environments/dev.yaml" UAT_VALUES_FILE: "devops/IaC/environments/uat.yaml" PROD_VALUES_FILE: "devops/IaC/environments/prod.yaml" # Branches DEV_BRANCH: "develop" UAT_BRANCH: "uat" PROD_BRANCH_PRIMARY: "main" # Namespaces DEV_NAMESPACE: "photoflow-dev" UAT_NAMESPACE: "photoflow-uat" PROD_NAMESPACE: "photoflow" # Toggle ENABLE_DEV_DEPLOY: "true" ENABLE_PROD_DEPLOY: "true"

Frontend Example

# pfl01y25-fe-web/.gitlab-ci.yml include: - project: 'shining-tree/devops/ci-templates' ref: develop file: 'pipelines/angular-app.yml' variables: SERVICE_NAME: "pfl-fe-web" IMAGE_PATH: "photo-flow/frontend/pfl01y25-fe-web" DEV_NAMESPACE: "photoflow-dev"

Helm Deployment

Deploy Script Logic

# Auto-compute IMAGE_TAG from DEPLOY_ENV case "$DEPLOY_ENV" in dev) IMAGE_TAG="dev" ;; beta) IMAGE_TAG="beta" ;; uat) IMAGE_TAG="uat" ;; prod) IMAGE_TAG="${CI_COMMIT_TAG:-latest}" ;; esac # Resolve namespace case "$DEPLOY_ENV" in dev) NAMESPACE="${DEV_NAMESPACE}" ;; uat) NAMESPACE="${UAT_NAMESPACE}" ;; prod) NAMESPACE="${PROD_NAMESPACE}" ;; esac # Helm deploy helm upgrade --install $HELM_RELEASE_NAME $CHART \ -n $NAMESPACE \ -f $HELM_VALUES_BASE/_global.yaml \ -f $HELM_VALUES_BASE/_ingress.yaml \ -f $HELM_VALUES_BASE/environments/$DEPLOY_ENV.yaml \ --set image.tag="$IMAGE_TAG" \ --set image.repository="$IMAGE_REPO"

Values File Structure

devops/IaC/ ├── _global.yaml # Global settings ├── _ingress.yaml # Ingress configuration ├── _containers/ # Container definitions │ ├── api.yaml │ └── worker.yaml └── environments/ ├── dev.yaml # Dev overrides ├── uat.yaml # UAT overrides └── prod.yaml # Production settings

Environment Configuration

Development

  • Namespace: photoflow-dev

  • URL: https://dev.api.photoflow.vn

  • Trigger: Auto-deploy on develop branch push

  • Image Tag: dev

UAT

  • Namespace: photoflow-uat

  • URL: https://uat.api.photoflow.vn

  • Trigger: Manual on uat branch

  • Image Tag: uat

Production

  • Namespace: photoflow

  • URL: https://api.photoflow.vn

  • Trigger: Manual on main branch or git tag

  • Image Tag: Git tag or latest

GitOps Integration

PhotoFlow uses GitOps for production deployments:

gitops-update: stage: deploy variables: GITOPS_REPO: "https://gitlab.com/photo-flow/photoflow-gitops.git" GITOPS_BRANCH: "main" script: - git clone $GITOPS_REPO - cd photoflow-gitops - yq e -i ".image.tag = \"$IMAGE_TAG\"" apps/$SERVICE_NAME/values.yaml - git commit -am "Update $SERVICE_NAME to $IMAGE_TAG" - git push

Rollback Procedures

Helm Rollback

# List releases helm history $HELM_RELEASE_NAME -n $NAMESPACE # Rollback to previous helm rollback $HELM_RELEASE_NAME -n $NAMESPACE # Rollback to specific revision helm rollback $HELM_RELEASE_NAME 5 -n $NAMESPACE

Deployment Rollback

# View rollout history kubectl rollout history deployment/$DEPLOY_NAME -n $NAMESPACE # Rollback to previous kubectl rollout undo deployment/$DEPLOY_NAME -n $NAMESPACE # Rollback to specific revision kubectl rollout undo deployment/$DEPLOY_NAME --to-revision=2 -n $NAMESPACE

Pipeline Troubleshooting

Common Issues

Issue

Cause

Solution

Build fails

Docker build error

Check Dockerfile, dependencies

Deploy times out

Pod startup issues

Check pod logs, resources

Helm error

Invalid values

Validate YAML syntax

Runner not found

Tag mismatch

Verify runner tags

Debugging Commands

# Check pipeline status gitlab-runner status # View pod logs kubectl logs -n $NAMESPACE deployment/$DEPLOY_NAME # Check Helm release helm get values $HELM_RELEASE_NAME -n $NAMESPACE # Describe failing pod kubectl describe pod -n $NAMESPACE -l app=$DEPLOY_NAME

Security

Secrets Management

Secrets are stored in GitLab CI/CD variables:

  • REGISTRY_PASSWORD - Container registry auth

  • KUBECONFIG - Kubernetes cluster access

  • GOOGLE_CREDENTIALS - Google Cloud auth

  • DATABASE_PASSWORD - Production DB password

Image Scanning

container-scan: stage: check image: aquasec/trivy:latest script: - trivy image --severity HIGH,CRITICAL $IMAGE_NAME:$IMAGE_TAG
Last modified: 25 February 2026