Skip to main content

Chapter 18: DevOps and CI/CD Integration

Overview

This chapter focuses on integrating Vektagraf applications into modern DevOps workflows and CI/CD pipelines. We'll explore automated testing strategies, infrastructure as code patterns, deployment automation, security scanning, and compliance validation to ensure reliable and secure delivery of Vektagraf applications.

Learning Objectives

  • Implement comprehensive CI/CD pipelines for Vektagraf applications
  • Master infrastructure as code patterns and configuration management
  • Set up automated deployment and rollback procedures
  • Integrate security scanning and compliance validation

Prerequisites

  • Understanding of CI/CD concepts and tools
  • Familiarity with containerization and Kubernetes
  • Knowledge of infrastructure as code principles
  • Basic understanding of security scanning and compliance

Core Concepts

CI/CD Pipeline Architecture

A comprehensive CI/CD pipeline for Vektagraf applications includes multiple stages:

graph LR
    A[Source Code] --> B[Build & Test]
    B --> C[Security Scan]
    C --> D[Package & Push]
    D --> E[Deploy to Staging]
    E --> F[Integration Tests]
    F --> G[Security Tests]
    G --> H[Deploy to Production]
    H --> I[Smoke Tests]
    I --> J[Monitor & Alert]

Pipeline Configuration

// lib/cicd/pipeline_config.dart
class PipelineConfig {
  final BuildConfig build;
  final TestConfig test;
  final SecurityConfig security;
  final DeploymentConfig deployment;
  
  const PipelineConfig({
    required this.build,
    required this.test,
    required this.security,
    required this.deployment,
  });
  
  Map<String, dynamic> toJson() => {
    'build': build.toJson(),
    'test': test.toJson(),
    'security': security.toJson(),
    'deployment': deployment.toJson(),
  };
}

class BuildConfig {
  final String dartVersion;
  final List<String> buildTargets;
  final bool enableOptimization;
  final Map<String, String> buildArgs;
  
  const BuildConfig({
    this.dartVersion = '3.0.0',
    this.buildTargets = const ['linux', 'docker'],
    this.enableOptimization = true,
    this.buildArgs = const {},
  });
  
  Map<String, dynamic> toJson() => {
    'dartVersion': dartVersion,
    'buildTargets': buildTargets,
    'enableOptimization': enableOptimization,
    'buildArgs': buildArgs,
  };
}

GitHub Actions CI/CD Pipeline

Complete Pipeline Configuration

# .github/workflows/ci-cd.yml
name: CI/CD Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]
  release:
    types: [published]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  # Build and Test Stage
  build-and-test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        dart-version: ['3.0.0', '3.1.0']
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
      with:
        fetch-depth: 0
    
    - name: Setup Dart
      uses: dart-lang/setup-dart@v1
      with:
        dart-version: ${{ matrix.dart-version }}
    
    - name: Cache dependencies
      uses: actions/cache@v3
      with:
        path: |
          ~/.pub-cache
          .dart_tool
        key: ${{ runner.os }}-dart-${{ matrix.dart-version }}-${{ hashFiles('**/pubspec.lock') }}
        restore-keys: |
          ${{ runner.os }}-dart-${{ matrix.dart-version }}-
    
    - name: Install dependencies
      run: dart pub get
    
    - name: Verify formatting
      run: dart format --output=none --set-exit-if-changed .
    
    - name: Analyze code
      run: dart analyze --fatal-infos
    
    - name: Run unit tests
      run: dart test --coverage=coverage
    
    - name: Generate coverage report
      run: |
        dart pub global activate coverage
        dart pub global run coverage:format_coverage \
          --lcov --in=coverage --out=coverage/lcov.info \
          --packages=.dart_tool/package_config.json \
          --report-on=lib
    
    - name: Upload coverage to Codecov
      uses: codecov/codecov-action@v3
      with:
        file: coverage/lcov.info
        flags: unittests
        name: codecov-umbrella
    
    - name: Build application
      run: |
        dart compile exe bin/server.dart -o build/vektagraf-server
        dart compile exe bin/client.dart -o build/vektagraf-client
    
    - name: Upload build artifacts
      uses: actions/upload-artifact@v3
      with:
        name: vektagraf-binaries-${{ matrix.dart-version }}
        path: build/

  # Security Scanning Stage
  security-scan:
    runs-on: ubuntu-latest
    needs: build-and-test
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Run Trivy vulnerability scanner
      uses: aquasecurity/trivy-action@master
      with:
        scan-type: 'fs'
        scan-ref: '.'
        format: 'sarif'
        output: 'trivy-results.sarif'
    
    - name: Upload Trivy scan results to GitHub Security tab
      uses: github/codeql-action/upload-sarif@v2
      with:
        sarif_file: 'trivy-results.sarif'
    
    - name: Run Semgrep security scan
      uses: returntocorp/semgrep-action@v1
      with:
        config: >-
          p/security-audit
          p/secrets
          p/dart
    
    - name: Dependency vulnerability scan
      run: |
        dart pub deps --json > deps.json
        # Custom script to check for known vulnerabilities
        python scripts/check_vulnerabilities.py deps.json

  # Container Build and Push Stage
  build-and-push:
    runs-on: ubuntu-latest
    needs: [build-and-test, security-scan]
    if: github.event_name != 'pull_request'
    
    permissions:
      contents: read
      packages: write
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v3
    
    - name: Log in to Container Registry
      uses: docker/login-action@v3
      with:
        registry: ${{ env.REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}
    
    - name: Extract metadata
      id: meta
      uses: docker/metadata-action@v5
      with:
        images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
        tags: |
          type=ref,event=branch
          type=ref,event=pr
          type=semver,pattern={{version}}
          type=semver,pattern={{major}}.{{minor}}
          type=sha,prefix={{branch}}-
    
    - name: Build and push Docker image
      uses: docker/build-push-action@v5
      with:
        context: .
        platforms: linux/amd64,linux/arm64
        push: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}
        cache-from: type=gha
        cache-to: type=gha,mode=max
        build-args: |
          VERSION=${{ github.sha }}
          BUILD_DATE=${{ github.event.head_commit.timestamp }}
    
    - name: Sign container image
      run: |
        cosign sign --yes ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
      env:
        COSIGN_EXPERIMENTAL: 1

  # Deploy to Staging
  deploy-staging:
    runs-on: ubuntu-latest
    needs: build-and-push
    if: github.ref == 'refs/heads/develop'
    environment: staging
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Configure kubectl
      uses: azure/k8s-set-context@v3
      with:
        method: kubeconfig
        kubeconfig: ${{ secrets.KUBE_CONFIG_STAGING }}
    
    - name: Deploy to staging
      run: |
        envsubst < k8s/staging/deployment.yaml | kubectl apply -f -
        kubectl rollout status deployment/vektagraf-app -n vektagraf-staging
      env:
        IMAGE_TAG: ${{ github.sha }}
    
    - name: Run smoke tests
      run: |
        kubectl wait --for=condition=ready pod -l app=vektagraf -n vektagraf-staging --timeout=300s
        ./scripts/smoke-tests.sh staging

  # Integration Tests
  integration-tests:
    runs-on: ubuntu-latest
    needs: deploy-staging
    if: github.ref == 'refs/heads/develop'
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Setup Dart
      uses: dart-lang/setup-dart@v1
    
    - name: Install dependencies
      run: dart pub get
    
    - name: Run integration tests
      run: dart test test/integration/
      env:
        VEKTAGRAF_ENDPOINT: ${{ secrets.STAGING_ENDPOINT }}
        VEKTAGRAF_API_KEY: ${{ secrets.STAGING_API_KEY }}
    
    - name: Run performance tests
      run: |
        dart run test/performance/load_test.dart
        dart run test/performance/stress_test.dart
    
    - name: Generate test report
      run: |
        dart run test/generate_report.dart
        
    - name: Upload test results
      uses: actions/upload-artifact@v3
      with:
        name: integration-test-results
        path: test-results/

  # Security Testing
  security-tests:
    runs-on: ubuntu-latest
    needs: deploy-staging
    if: github.ref == 'refs/heads/develop'
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Run OWASP ZAP security scan
      uses: zaproxy/action-full-scan@v0.7.0
      with:
        target: ${{ secrets.STAGING_ENDPOINT }}
        rules_file_name: '.zap/rules.tsv'
        cmd_options: '-a'
    
    - name: Run custom security tests
      run: |
        dart test test/security/
      env:
        TARGET_ENDPOINT: ${{ secrets.STAGING_ENDPOINT }}
    
    - name: Upload security scan results
      uses: actions/upload-artifact@v3
      with:
        name: security-scan-results
        path: report_html.html

  # Deploy to Production
  deploy-production:
    runs-on: ubuntu-latest
    needs: [integration-tests, security-tests]
    if: github.event_name == 'release'
    environment: production
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Configure kubectl
      uses: azure/k8s-set-context@v3
      with:
        method: kubeconfig
        kubeconfig: ${{ secrets.KUBE_CONFIG_PRODUCTION }}
    
    - name: Deploy with blue-green strategy
      run: |
        ./scripts/blue-green-deploy.sh ${{ github.event.release.tag_name }}
    
    - name: Run production smoke tests
      run: |
        ./scripts/smoke-tests.sh production
    
    - name: Update monitoring dashboards
      run: |
        ./scripts/update-dashboards.sh ${{ github.event.release.tag_name }}

  # Post-deployment monitoring
  post-deployment:
    runs-on: ubuntu-latest
    needs: deploy-production
    if: github.event_name == 'release'
    
    steps:
    - name: Monitor deployment health
      run: |
        ./scripts/monitor-deployment.sh 300  # Monitor for 5 minutes
    
    - name: Send deployment notification
      uses: 8398a7/action-slack@v3
      with:
        status: ${{ job.status }}
        channel: '#deployments'
        webhook_url: ${{ secrets.SLACK_WEBHOOK }}
        fields: repo,message,commit,author,action,eventName,ref,workflow

Advanced Pipeline Features

Parallel Testing Strategy

# .github/workflows/parallel-tests.yml
name: Parallel Test Execution

on:
  pull_request:
    branches: [main]

jobs:
  test-matrix:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        test-suite:
          - unit
          - integration
          - performance
          - security
        dart-version: ['3.0.0', '3.1.0']
        database-mode: ['embedded', 'hosted']
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Setup Dart
      uses: dart-lang/setup-dart@v1
      with:
        dart-version: ${{ matrix.dart-version }}
    
    - name: Setup test environment
      run: |
        case "${{ matrix.test-suite }}" in
          "unit")
            echo "Running unit tests"
            ;;
          "integration")
            docker-compose -f docker-compose.test.yml up -d
            ;;
          "performance")
            ./scripts/setup-performance-env.sh
            ;;
          "security")
            ./scripts/setup-security-env.sh
            ;;
        esac
    
    - name: Run tests
      run: |
        dart test test/${{ matrix.test-suite }}/ \
          --define=database-mode=${{ matrix.database-mode }}
    
    - name: Upload test results
      uses: actions/upload-artifact@v3
      with:
        name: test-results-${{ matrix.test-suite }}-${{ matrix.dart-version }}-${{ matrix.database-mode }}
        path: test-results/

Infrastructure as Code

Terraform Configuration

Main Infrastructure

# terraform/main.tf
terraform {
  required_version = ">= 1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = "~> 2.20"
    }
  }
  
  backend "s3" {
    bucket = "vektagraf-terraform-state"
    key    = "infrastructure/terraform.tfstate"
    region = "us-east-1"
  }
}

provider "aws" {
  region = var.aws_region
}

provider "kubernetes" {
  host                   = module.eks.cluster_endpoint
  cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
  
  exec {
    api_version = "client.authentication.k8s.io/v1beta1"
    command     = "aws"
    args        = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
  }
}

# VPC Configuration
module "vpc" {
  source = "terraform-aws-modules/vpc/aws"
  
  name = "${var.project_name}-vpc"
  cidr = var.vpc_cidr
  
  azs             = var.availability_zones
  private_subnets = var.private_subnets
  public_subnets  = var.public_subnets
  
  enable_nat_gateway = true
  enable_vpn_gateway = false
  enable_dns_hostnames = true
  enable_dns_support = true
  
  tags = var.common_tags
}

# EKS Cluster
module "eks" {
  source = "terraform-aws-modules/eks/aws"
  
  cluster_name    = "${var.project_name}-cluster"
  cluster_version = var.kubernetes_version
  
  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnets
  
  cluster_endpoint_config = {
    private_access = true
    public_access  = true
    public_access_cidrs = var.allowed_cidrs
  }
  
  # Node groups
  eks_managed_node_groups = {
    main = {
      min_size     = var.node_group_min_size
      max_size     = var.node_group_max_size
      desired_size = var.node_group_desired_size
      
      instance_types = var.node_instance_types
      capacity_type  = "ON_DEMAND"
      
      k8s_labels = {
        Environment = var.environment
        Application = "vektagraf"
      }
      
      update_config = {
        max_unavailable_percentage = 25
      }
    }
    
    spot = {
      min_size     = 0
      max_size     = 10
      desired_size = 2
      
      instance_types = var.spot_instance_types
      capacity_type  = "SPOT"
      
      k8s_labels = {
        Environment = var.environment
        Application = "vektagraf"
        NodeType    = "spot"
      }
      
      taints = {
        spot = {
          key    = "spot-instance"
          value  = "true"
          effect = "NO_SCHEDULE"
        }
      }
    }
  }
  
  tags = var.common_tags
}

# RDS for metadata storage
resource "aws_db_instance" "metadata" {
  identifier = "${var.project_name}-metadata"
  
  engine         = "postgres"
  engine_version = "15.3"
  instance_class = var.rds_instance_class
  
  allocated_storage     = var.rds_allocated_storage
  max_allocated_storage = var.rds_max_allocated_storage
  storage_type          = "gp3"
  storage_encrypted     = true
  
  db_name  = "vektagraf_metadata"
  username = var.rds_username
  password = var.rds_password
  
  vpc_security_group_ids = [aws_security_group.rds.id]
  db_subnet_group_name   = aws_db_subnet_group.main.name
  
  backup_retention_period = var.rds_backup_retention
  backup_window          = "03:00-04:00"
  maintenance_window     = "sun:04:00-sun:05:00"
  
  skip_final_snapshot = var.environment != "production"
  deletion_protection = var.environment == "production"
  
  tags = var.common_tags
}

# ElastiCache for caching
resource "aws_elasticache_replication_group" "cache" {
  replication_group_id       = "${var.project_name}-cache"
  description                = "Vektagraf Redis cache"
  
  node_type                  = var.redis_node_type
  port                       = 6379
  parameter_group_name       = "default.redis7"
  
  num_cache_clusters         = var.redis_num_nodes
  automatic_failover_enabled = var.redis_num_nodes > 1
  multi_az_enabled          = var.redis_num_nodes > 1
  
  subnet_group_name = aws_elasticache_subnet_group.main.name
  security_group_ids = [aws_security_group.redis.id]
  
  at_rest_encryption_enabled = true
  transit_encryption_enabled = true
  
  tags = var.common_tags
}

Variables Configuration

# terraform/variables.tf
variable "project_name" {
  description = "Name of the project"
  type        = string
  default     = "vektagraf"
}

variable "environment" {
  description = "Environment name"
  type        = string
  validation {
    condition     = contains(["development", "staging", "production"], var.environment)
    error_message = "Environment must be development, staging, or production."
  }
}

variable "aws_region" {
  description = "AWS region"
  type        = string
  default     = "us-east-1"
}

variable "vpc_cidr" {
  description = "CIDR block for VPC"
  type        = string
  default     = "10.0.0.0/16"
}

variable "availability_zones" {
  description = "Availability zones"
  type        = list(string)
  default     = ["us-east-1a", "us-east-1b", "us-east-1c"]
}

variable "private_subnets" {
  description = "Private subnet CIDR blocks"
  type        = list(string)
  default     = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
}

variable "public_subnets" {
  description = "Public subnet CIDR blocks"
  type        = list(string)
  default     = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
}

variable "kubernetes_version" {
  description = "Kubernetes version"
  type        = string
  default     = "1.27"
}

variable "node_group_min_size" {
  description = "Minimum number of nodes in the node group"
  type        = number
  default     = 1
}

variable "node_group_max_size" {
  description = "Maximum number of nodes in the node group"
  type        = number
  default     = 10
}

variable "node_group_desired_size" {
  description = "Desired number of nodes in the node group"
  type        = number
  default     = 3
}

variable "node_instance_types" {
  description = "Instance types for the node group"
  type        = list(string)
  default     = ["t3.medium", "t3.large"]
}

variable "common_tags" {
  description = "Common tags to apply to all resources"
  type        = map(string)
  default = {
    Project     = "vektagraf"
    ManagedBy   = "terraform"
  }
}

Environment-Specific Configurations

# terraform/environments/production.tfvars
environment = "production"
aws_region  = "us-east-1"

# EKS Configuration
kubernetes_version = "1.27"
node_group_min_size = 3
node_group_max_size = 20
node_group_desired_size = 6
node_instance_types = ["m5.large", "m5.xlarge"]

# RDS Configuration
rds_instance_class = "db.r6g.large"
rds_allocated_storage = 100
rds_max_allocated_storage = 1000
rds_backup_retention = 30

# Redis Configuration
redis_node_type = "cache.r6g.large"
redis_num_nodes = 3

# Security
allowed_cidrs = ["10.0.0.0/8"]

common_tags = {
  Project     = "vektagraf"
  Environment = "production"
  ManagedBy   = "terraform"
  CostCenter  = "engineering"
}

Helm Charts

Vektagraf Application Chart

# helm/vektagraf/Chart.yaml
apiVersion: v2
name: vektagraf
description: A Helm chart for Vektagraf application
type: application
version: 0.1.0
appVersion: "1.0.0"

dependencies:
- name: postgresql
  version: "12.x.x"
  repository: "https://charts.bitnami.com/bitnami"
  condition: postgresql.enabled
- name: redis
  version: "17.x.x"
  repository: "https://charts.bitnami.com/bitnami"
  condition: redis.enabled
# helm/vektagraf/values.yaml
# Default values for vektagraf
replicaCount: 3

image:
  repository: ghcr.io/yourorg/vektagraf
  pullPolicy: IfNotPresent
  tag: ""

imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""

serviceAccount:
  create: true
  annotations: {}
  name: ""

podAnnotations:
  prometheus.io/scrape: "true"
  prometheus.io/port: "8080"
  prometheus.io/path: "/metrics"

podSecurityContext:
  fsGroup: 1000
  runAsNonRoot: true
  runAsUser: 1000

securityContext:
  allowPrivilegeEscalation: false
  capabilities:
    drop:
    - ALL
  readOnlyRootFilesystem: true

service:
  type: ClusterIP
  port: 80
  targetPort: 8080

ingress:
  enabled: true
  className: "nginx"
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/rate-limit: "100"
  hosts:
  - host: api.yourdomain.com
    paths:
    - path: /
      pathType: Prefix
  tls:
  - secretName: vektagraf-tls
    hosts:
    - api.yourdomain.com

resources:
  limits:
    cpu: 2000m
    memory: 4Gi
  requests:
    cpu: 500m
    memory: 1Gi

autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 20
  targetCPUUtilizationPercentage: 70
  targetMemoryUtilizationPercentage: 80

nodeSelector: {}

tolerations: []

affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 100
      podAffinityTerm:
        labelSelector:
          matchExpressions:
          - key: app.kubernetes.io/name
            operator: In
            values:
            - vektagraf
        topologyKey: kubernetes.io/hostname

# Vektagraf specific configuration
vektagraf:
  config:
    database:
      mode: hosted
      maxConnections: 100
      connectionTimeout: "30s"
    vector:
      algorithm: hnsw
      dimensions: 768
      efConstruction: 200
    security:
      encryptionEnabled: true
      auditLogging: true
      rateLimiting:
        enabled: true
        requestsPerMinute: 1000

# External dependencies
postgresql:
  enabled: true
  auth:
    postgresPassword: "changeme"
    database: "vektagraf"
  primary:
    persistence:
      enabled: true
      size: 100Gi

redis:
  enabled: true
  auth:
    enabled: true
    password: "changeme"
  master:
    persistence:
      enabled: true
      size: 10Gi
# helm/vektagraf/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "vektagraf.fullname" . }}
  labels:
    {{- include "vektagraf.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include "vektagraf.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
        {{- with .Values.podAnnotations }}
        {{- toYaml . | nindent 8 }}
        {{- end }}
      labels:
        {{- include "vektagraf.selectorLabels" . | nindent 8 }}
    spec:
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      serviceAccountName: {{ include "vektagraf.serviceAccountName" . }}
      securityContext:
        {{- toYaml .Values.podSecurityContext | nindent 8 }}
      containers:
      - name: {{ .Chart.Name }}
        securityContext:
          {{- toYaml .Values.securityContext | nindent 12 }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        ports:
        - name: http
          containerPort: 8080
          protocol: TCP
        - name: grpc
          containerPort: 9090
          protocol: TCP
        livenessProbe:
          httpGet:
            path: /health
            port: http
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: http
          initialDelaySeconds: 5
          periodSeconds: 5
        startupProbe:
          httpGet:
            path: /health
            port: http
          initialDelaySeconds: 10
          periodSeconds: 10
          failureThreshold: 30
        env:
        - name: VEKTAGRAF_CONFIG_PATH
          value: "/config/app.json"
        - name: DATABASE_PASSWORD
          valueFrom:
            secretKeyRef:
              name: {{ include "vektagraf.fullname" . }}-secrets
              key: database-password
        - name: ENCRYPTION_KEY
          valueFrom:
            secretKeyRef:
              name: {{ include "vektagraf.fullname" . }}-secrets
              key: encryption-key
        volumeMounts:
        - name: config
          mountPath: /config
        - name: data
          mountPath: /data
        - name: tmp
          mountPath: /tmp
        resources:
          {{- toYaml .Values.resources | nindent 12 }}
      volumes:
      - name: config
        configMap:
          name: {{ include "vektagraf.fullname" . }}-config
      - name: data
        persistentVolumeClaim:
          claimName: {{ include "vektagraf.fullname" . }}-data
      - name: tmp
        emptyDir: {}
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.affinity }}
      affinity:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.tolerations }}
      tolerations:
        {{- toYaml . | nindent 8 }}
      {{- end }}

Configuration Management

GitOps with ArgoCD

Application Configuration

# argocd/applications/vektagraf-production.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: vektagraf-production
  namespace: argocd
  finalizers:
  - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://github.com/yourorg/vektagraf-config
    targetRevision: main
    path: environments/production
    helm:
      valueFiles:
      - values.yaml
      - secrets.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: vektagraf-production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
      allowEmpty: false
    syncOptions:
    - CreateNamespace=true
    - PrunePropagationPolicy=foreground
    - PruneLast=true
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m
  revisionHistoryLimit: 10

Multi-Environment Configuration

# argocd/app-of-apps.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: vektagraf-environments
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/yourorg/vektagraf-config
    targetRevision: main
    path: argocd/applications
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Secrets Management with External Secrets Operator

# external-secrets/secret-store.yaml
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: aws-secrets-manager
  namespace: vektagraf-production
spec:
  provider:
    aws:
      service: SecretsManager
      region: us-east-1
      auth:
        jwt:
          serviceAccountRef:
            name: external-secrets-sa
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: vektagraf-secrets
  namespace: vektagraf-production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: SecretStore
  target:
    name: vektagraf-secrets
    creationPolicy: Owner
  data:
  - secretKey: database-password
    remoteRef:
      key: vektagraf/production/database
      property: password
  - secretKey: encryption-key
    remoteRef:
      key: vektagraf/production/encryption
      property: key
  - secretKey: jwt-secret
    remoteRef:
      key: vektagraf/production/jwt
      property: secret

Automated Deployment and Rollback

Blue-Green Deployment Script

#!/bin/bash
# scripts/blue-green-deploy.sh

set -euo pipefail

NAMESPACE="${NAMESPACE:-vektagraf-production}"
NEW_VERSION="$1"
TIMEOUT="${TIMEOUT:-600}"

if [ -z "$NEW_VERSION" ]; then
    echo "Usage: $0 <version>"
    exit 1
fi

echo "Starting blue-green deployment for version: $NEW_VERSION"

# Get current active color
CURRENT_COLOR=$(kubectl get service vektagraf-active -n "$NAMESPACE" \
    -o jsonpath='{.spec.selector.version}' 2>/dev/null || echo "blue")

if [ "$CURRENT_COLOR" = "blue" ]; then
    NEW_COLOR="green"
else
    NEW_COLOR="blue"
fi

echo "Current active: $CURRENT_COLOR, deploying to: $NEW_COLOR"

# Update deployment with new version
kubectl patch deployment "vektagraf-$NEW_COLOR" -n "$NAMESPACE" \
    -p '{"spec":{"template":{"spec":{"containers":[{"name":"vektagraf","image":"ghcr.io/yourorg/vektagraf:'$NEW_VERSION'"}]}}}}'

# Wait for rollout to complete
echo "Waiting for rollout to complete..."
kubectl rollout status deployment/"vektagraf-$NEW_COLOR" -n "$NAMESPACE" --timeout="${TIMEOUT}s"

# Run health checks
echo "Running health checks..."
for i in {1..30}; do
    if kubectl run health-check-$NEW_COLOR-$i \
        --image=curlimages/curl \
        --rm -i --restart=Never \
        --timeout=10s \
        --command -- curl -f "http://vektagraf-$NEW_COLOR/health" >/dev/null 2>&1; then
        echo "Health check passed"
        break
    fi
    
    if [ $i -eq 30 ]; then
        echo "Health checks failed"
        exit 1
    fi
    
    echo "Health check $i failed, retrying..."
    sleep 10
done

# Run smoke tests
echo "Running smoke tests..."
if ! ./scripts/smoke-tests.sh "$NEW_COLOR" "$NAMESPACE"; then
    echo "Smoke tests failed"
    exit 1
fi

# Switch traffic
echo "Switching traffic to $NEW_COLOR..."
kubectl patch service vektagraf-active -n "$NAMESPACE" \
    -p '{"spec":{"selector":{"version":"'$NEW_COLOR'"}}}'

# Verify traffic switch
sleep 10
echo "Verifying traffic switch..."
for i in {1..10}; do
    if kubectl run verify-traffic-$i \
        --image=curlimages/curl \
        --rm -i --restart=Never \
        --timeout=10s \
        --command -- curl -f "http://vektagraf-active/health" >/dev/null 2>&1; then
        echo "Traffic switch verified"
        break
    fi
    
    if [ $i -eq 10 ]; then
        echo "Traffic switch verification failed, rolling back..."
        kubectl patch service vektagraf-active -n "$NAMESPACE" \
            -p '{"spec":{"selector":{"version":"'$CURRENT_COLOR'"}}}'
        exit 1
    fi
    
    sleep 5
done

echo "Blue-green deployment completed successfully"
echo "Active color is now: $NEW_COLOR"

# Optional: Scale down old version after verification period
read -p "Scale down $CURRENT_COLOR deployment? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
    kubectl scale deployment "vektagraf-$CURRENT_COLOR" --replicas=0 -n "$NAMESPACE"
    echo "Scaled down $CURRENT_COLOR deployment"
fi

Automated Rollback

#!/bin/bash
# scripts/rollback.sh

set -euo pipefail

NAMESPACE="${NAMESPACE:-vektagraf-production}"
REASON="${1:-Manual rollback}"

echo "Initiating rollback: $REASON"

# Get current and previous colors
CURRENT_COLOR=$(kubectl get service vektagraf-active -n "$NAMESPACE" \
    -o jsonpath='{.spec.selector.version}')

if [ "$CURRENT_COLOR" = "blue" ]; then
    PREVIOUS_COLOR="green"
else
    PREVIOUS_COLOR="blue"
fi

echo "Rolling back from $CURRENT_COLOR to $PREVIOUS_COLOR"

# Check if previous deployment is available
if ! kubectl get deployment "vektagraf-$PREVIOUS_COLOR" -n "$NAMESPACE" >/dev/null 2>&1; then
    echo "Previous deployment not found"
    exit 1
fi

# Scale up previous deployment if needed
PREVIOUS_REPLICAS=$(kubectl get deployment "vektagraf-$PREVIOUS_COLOR" -n "$NAMESPACE" \
    -o jsonpath='{.spec.replicas}')

if [ "$PREVIOUS_REPLICAS" -eq 0 ]; then
    echo "Scaling up previous deployment..."
    kubectl scale deployment "vektagraf-$PREVIOUS_COLOR" --replicas=3 -n "$NAMESPACE"
    kubectl rollout status deployment/"vektagraf-$PREVIOUS_COLOR" -n "$NAMESPACE"
fi

# Run health checks on previous deployment
echo "Running health checks on previous deployment..."
for i in {1..10}; do
    if kubectl run rollback-health-check-$i \
        --image=curlimages/curl \
        --rm -i --restart=Never \
        --timeout=10s \
        --command -- curl -f "http://vektagraf-$PREVIOUS_COLOR/health" >/dev/null 2>&1; then
        echo "Health check passed"
        break
    fi
    
    if [ $i -eq 10 ]; then
        echo "Health checks failed on previous deployment"
        exit 1
    fi
    
    sleep 5
done

# Switch traffic back
echo "Switching traffic back to $PREVIOUS_COLOR..."
kubectl patch service vektagraf-active -n "$NAMESPACE" \
    -p '{"spec":{"selector":{"version":"'$PREVIOUS_COLOR'"}}}'

# Scale down current deployment
echo "Scaling down current deployment..."
kubectl scale deployment "vektagraf-$CURRENT_COLOR" --replicas=0 -n "$NAMESPACE"

echo "Rollback completed successfully"

# Send notification
curl -X POST "$SLACK_WEBHOOK_URL" \
    -H 'Content-type: application/json' \
    --data "{\"text\":\"🔄 Rollback completed: $REASON\"}"

Security Scanning and Compliance

Container Security Scanning

# .github/workflows/security-scan.yml
name: Security Scan

on:
  push:
    branches: [main]
  schedule:
    - cron: '0 2 * * *'  # Daily at 2 AM

jobs:
  container-scan:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Build image
      run: docker build -t vektagraf:scan .
    
    - name: Run Trivy vulnerability scanner
      uses: aquasecurity/trivy-action@master
      with:
        image-ref: 'vektagraf:scan'
        format: 'json'
        output: 'trivy-results.json'
    
    - name: Run Grype vulnerability scanner
      uses: anchore/scan-action@v3
      with:
        image: 'vektagraf:scan'
        format: 'json'
        output-file: 'grype-results.json'
    
    - name: Run Snyk container scan
      uses: snyk/actions/docker@master
      env:
        SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
      with:
        image: 'vektagraf:scan'
        args: --severity-threshold=high --json-file-output=snyk-results.json
    
    - name: Process scan results
      run: |
        python scripts/process-security-results.py \
          --trivy trivy-results.json \
          --grype grype-results.json \
          --snyk snyk-results.json \
          --output security-report.json
    
    - name: Upload security report
      uses: actions/upload-artifact@v3
      with:
        name: security-report
        path: security-report.json
    
    - name: Check security thresholds
      run: |
        python scripts/check-security-thresholds.py security-report.json

Compliance Validation

// lib/compliance/compliance_validator.dart
class ComplianceValidator {
  final List<ComplianceRule> rules;
  
  ComplianceValidator({required this.rules});
  
  Future<ComplianceReport> validate(VektagrafConfig config) async {
    final results = <ComplianceResult>[];
    
    for (final rule in rules) {
      try {
        final result = await rule.validate(config);
        results.add(result);
      } catch (e) {
        results.add(ComplianceResult(
          rule: rule,
          status: ComplianceStatus.error,
          message: 'Validation error: $e',
        ));
      }
    }
    
    return ComplianceReport(
      timestamp: DateTime.now(),
      results: results,
      overallStatus: _calculateOverallStatus(results),
    );
  }
  
  ComplianceStatus _calculateOverallStatus(List<ComplianceResult> results) {
    if (results.any((r) => r.status == ComplianceStatus.failed)) {
      return ComplianceStatus.failed;
    }
    if (results.any((r) => r.status == ComplianceStatus.warning)) {
      return ComplianceStatus.warning;
    }
    return ComplianceStatus.passed;
  }
}

abstract class ComplianceRule {
  String get name;
  String get description;
  ComplianceFramework get framework;
  
  Future<ComplianceResult> validate(VektagrafConfig config);
}

class EncryptionAtRestRule implements ComplianceRule {
  @override
  String get name => 'Encryption at Rest';
  
  @override
  String get description => 'Data must be encrypted at rest';
  
  @override
  ComplianceFramework get framework => ComplianceFramework.gdpr;
  
  @override
  Future<ComplianceResult> validate(VektagrafConfig config) async {
    if (!config.security.encryptionEnabled) {
      return ComplianceResult(
        rule: this,
        status: ComplianceStatus.failed,
        message: 'Encryption at rest is not enabled',
      );
    }
    
    return ComplianceResult(
      rule: this,
      status: ComplianceStatus.passed,
      message: 'Encryption at rest is properly configured',
    );
  }
}

class AuditLoggingRule implements ComplianceRule {
  @override
  String get name => 'Audit Logging';
  
  @override
  String get description => 'All data access must be logged';
  
  @override
  ComplianceFramework get framework => ComplianceFramework.sox;
  
  @override
  Future<ComplianceResult> validate(VektagrafConfig config) async {
    if (!config.security.auditLogging) {
      return ComplianceResult(
        rule: this,
        status: ComplianceStatus.failed,
        message: 'Audit logging is not enabled',
      );
    }
    
    return ComplianceResult(
      rule: this,
      status: ComplianceStatus.passed,
      message: 'Audit logging is properly configured',
    );
  }
}

enum ComplianceFramework { gdpr, hipaa, sox, pci }
enum ComplianceStatus { passed, warning, failed, error }

class ComplianceResult {
  final ComplianceRule rule;
  final ComplianceStatus status;
  final String message;
  
  const ComplianceResult({
    required this.rule,
    required this.status,
    required this.message,
  });
}

class ComplianceReport {
  final DateTime timestamp;
  final List<ComplianceResult> results;
  final ComplianceStatus overallStatus;
  
  const ComplianceReport({
    required this.timestamp,
    required this.results,
    required this.overallStatus,
  });
  
  Map<String, dynamic> toJson() => {
    'timestamp': timestamp.toIso8601String(),
    'overallStatus': overallStatus.name,
    'results': results.map((r) => {
      'rule': r.rule.name,
      'framework': r.rule.framework.name,
      'status': r.status.name,
      'message': r.message,
    }).toList(),
  };
}

Automated Compliance Testing

# .github/workflows/compliance.yml
name: Compliance Validation

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  compliance-check:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Setup Dart
      uses: dart-lang/setup-dart@v1
    
    - name: Install dependencies
      run: dart pub get
    
    - name: Run compliance validation
      run: dart run bin/compliance_validator.dart
    
    - name: Generate compliance report
      run: |
        dart run bin/generate_compliance_report.dart \
          --output compliance-report.json \
          --format json
    
    - name: Upload compliance report
      uses: actions/upload-artifact@v3
      with:
        name: compliance-report
        path: compliance-report.json
    
    - name: Check compliance status
      run: |
        if ! dart run bin/check_compliance_status.dart compliance-report.json; then
          echo "Compliance validation failed"
          exit 1
        fi

Best Practices

CI/CD Best Practices

  1. Pipeline Security

    • Use least privilege access
    • Secure secrets management
    • Regular security scanning
    • Audit pipeline activities
  2. Testing Strategy

    • Comprehensive test coverage
    • Parallel test execution
    • Environment-specific testing
    • Performance and security testing
  3. Deployment Safety

    • Blue-green deployments
    • Automated rollback procedures
    • Health checks and monitoring
    • Gradual traffic shifting

Infrastructure Best Practices

  1. Infrastructure as Code

    • Version control all infrastructure
    • Use modules and reusable components
    • Implement proper state management
    • Regular infrastructure testing
  2. Configuration Management

    • GitOps workflows
    • Environment-specific configurations
    • Secure secrets handling
    • Configuration validation
  3. Monitoring and Observability

    • Comprehensive monitoring setup
    • Automated alerting
    • Performance tracking
    • Audit logging

Advanced Topics

Multi-Cloud Deployment

# terraform/multi-cloud/main.tf
# AWS Provider
provider "aws" {
  alias  = "primary"
  region = "us-east-1"
}

# GCP Provider
provider "google" {
  alias   = "secondary"
  project = var.gcp_project_id
  region  = "us-central1"
}

# Azure Provider
provider "azurerm" {
  alias = "tertiary"
  features {}
}

# Multi-cloud load balancer
resource "cloudflare_load_balancer" "global" {
  zone_id = var.cloudflare_zone_id
  name    = "vektagraf-global"
  
  fallback_pool_id = cloudflare_load_balancer_pool.aws.id
  
  default_pool_ids = [
    cloudflare_load_balancer_pool.aws.id,
    cloudflare_load_balancer_pool.gcp.id,
  ]
  
  region_pools = {
    "WNAM" = [cloudflare_load_balancer_pool.aws.id]
    "ENAM" = [cloudflare_load_balancer_pool.gcp.id]
    "EU"   = [cloudflare_load_balancer_pool.azure.id]
  }
}

Progressive Delivery with Flagger

# flagger/canary.yaml
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: vektagraf-canary
  namespace: vektagraf-production
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: vektagraf-app
  progressDeadlineSeconds: 60
  service:
    port: 80
    targetPort: 8080
  analysis:
    interval: 1m
    threshold: 5
    maxWeight: 50
    stepWeight: 10
    metrics:
    - name: request-success-rate
      thresholdRange:
        min: 99
      interval: 1m
    - name: request-duration
      thresholdRange:
        max: 500
      interval: 1m
    - name: vektagraf-error-rate
      templateRef:
        name: vektagraf-error-rate
      thresholdRange:
        max: 1
      interval: 1m
    webhooks:
    - name: acceptance-test
      type: pre-rollout
      url: http://flagger-loadtester.test/
      timeout: 30s
      metadata:
        type: bash
        cmd: "curl -sd 'test' http://vektagraf-canary/api/test | grep OK"
    - name: load-test
      url: http://flagger-loadtester.test/
      timeout: 5s
      metadata:
        cmd: "hey -z 1m -q 10 -c 2 http://vektagraf-canary/"

Summary

This chapter covered comprehensive DevOps and CI/CD integration for Vektagraf applications, including:

  • CI/CD Pipelines: Complete GitHub Actions workflows with testing and deployment
  • Infrastructure as Code: Terraform configurations for scalable infrastructure
  • Configuration Management: GitOps with ArgoCD and Helm charts
  • Automated Deployment: Blue-green and canary deployment strategies
  • Security Integration: Container scanning and compliance validation
  • Best Practices: Security, testing, and operational excellence

Key Takeaways

  1. Implement comprehensive CI/CD pipelines with proper testing
  2. Use infrastructure as code for reproducible deployments
  3. Adopt GitOps for configuration management
  4. Implement progressive deployment strategies
  5. Integrate security scanning throughout the pipeline
  6. Maintain compliance through automated validation

Next Steps

  • Chapter 19: Learn about troubleshooting and maintenance procedures