Deployment Domination: Master Docker & Kubernetes for ASP.NET Core Apps
Master ASP.NET Core deployment with Docker & Kubernetes. Step-by-step containerization, orchestration, CI/CD, and production best practices for scalable apps.
ASPNETCore,Docker,Kubernetes,Deployment,DevOps,Containers,Microservices,CloudNative,Azure,AWS,Production,CI/CD,Containerization,Orchestration
Table of Contents
1. Introduction to Containerization
The Evolution of Application Deployment
Traditional deployment methodologies often led to the infamous "it works on my machine" syndrome. Containerization revolutionizes this by packaging applications with their dependencies, ensuring consistency across environments.
Real-World Analogy: Think of containers as shipping containers in the logistics industry. Just as standardized containers can be transported via ship, train, or truck without opening, software containers run consistently regardless of the underlying infrastructure.
Why Containerization Matters for ASP.NET Core
// Traditional deployment challenges
public class DeploymentPainPoints
{
    public List<string> CommonIssues = new()
    {
        "Dependency version conflicts",
        "Environment configuration mismatches",
        "Inconsistent runtime behavior",
        "Difficult scaling operations",
        "Long deployment cycles"
    };
}
// Traditional deployment challenges public class DeploymentPainPoints { public List<string> CommonIssues = new() { "Dependency version conflicts", "Environment configuration mismatches", "Inconsistent runtime behavior", "Difficult scaling operations", "Long deployment cycles" }; }
Benefits Overview
Consistency: Identical environments from development to production
Isolation: Applications run in isolated environments
Portability: Run anywhere Docker is supported
Scalability: Easy horizontal scaling
Resource Efficiency: Better utilization than virtual machines
Consistency: Identical environments from development to production
Isolation: Applications run in isolated environments
Portability: Run anywhere Docker is supported
Scalability: Easy horizontal scaling
Resource Efficiency: Better utilization than virtual machines
2. Docker Fundamentals
Docker Architecture Deep Dive
# Understanding Docker components
Docker Ecosystem:
  Docker Engine:
    - Docker Daemon
    - Docker Client
    - REST API
  Docker Images: Immutable templates
  Docker Containers: Runnable instances
  Docker Registry: Image storage (Docker Hub, Azure Container Registry)
  Docker Compose: Multi-container applications
# Understanding Docker components Docker Ecosystem: Docker Engine: - Docker Daemon - Docker Client - REST API Docker Images: Immutable templates Docker Containers: Runnable instances Docker Registry: Image storage (Docker Hub, Azure Container Registry) Docker Compose: Multi-container applications
Essential Docker Commands
# Image management
docker build -t myapp:latest .
docker images
docker rmi <image_id>
# Container operations
docker run -d -p 8080:80 --name myapp myapp:latest
docker ps
docker stop <container_id>
docker logs <container_id>
# System management
docker system prune
docker stats
# Image management docker build -t myapp:latest . docker images docker rmi <image_id> # Container operations docker run -d -p 8080:80 --name myapp myapp:latest docker ps docker stop <container_id> docker logs <container_id> # System management docker system prune docker stats
Dockerfile Anatomy
# Base image
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
# Build stage
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["MyApp/MyApp.csproj", "MyApp/"]
RUN dotnet restore "MyApp/MyApp.csproj"
COPY . .
WORKDIR "/src/MyApp"
RUN dotnet build "MyApp.csproj" -c Release -o /app/build
# Publish stage
FROM build AS publish
RUN dotnet publish "MyApp.csproj" -c Release -o /app/publish
# Final stage
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyApp.dll"]
# Base image FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base WORKDIR /app EXPOSE 80 EXPOSE 443 # Build stage FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY ["MyApp/MyApp.csproj", "MyApp/"] RUN dotnet restore "MyApp/MyApp.csproj" COPY . . WORKDIR "/src/MyApp" RUN dotnet build "MyApp.csproj" -c Release -o /app/build # Publish stage FROM build AS publish RUN dotnet publish "MyApp.csproj" -c Release -o /app/publish # Final stage FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "MyApp.dll"]
3. ASP.NET Core Dockerization
Basic Docker Configuration
Let's create a real-world e-commerce application and containerize it step by step.
Project Structure:
ECommerceApp/ ├── src/ │ ├── ECommerce.API/ │ ├── ECommerce.Services/ │ └── ECommerce.Data/ ├── tests/ ├── docker-compose.yml └── Dockerfile
Complete Docker Implementation
// Program.cs - Modern minimal API approach
using ECommerce.API;
using ECommerce.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to container
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Database configuration with environment flexibility
builder.Services.AddDbContext<ECommerceContext>(options =>
{
    var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
    if (builder.Environment.IsProduction())
    {
        options.UseSqlServer(connectionString, 
            sqlOptions => sqlOptions.EnableRetryOnFailure());
    }
    else
    {
        options.UseSqlServer(connectionString);
    }
});
// Health checks
builder.Services.AddHealthChecks()
    .AddDbContextCheck<ECommerceContext>();
var app = builder.Build();
// Configure pipeline
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.MapHealthChecks("/health");
app.Run();
# Multi-stage Dockerfile for ASP.NET Core
# Stage 1: Base
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
# Install curl for health checks
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
# Stage 2: Build
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
# Copy project files
COPY ["src/ECommerce.API/ECommerce.API.csproj", "src/ECommerce.API/"]
COPY ["src/ECommerce.Services/ECommerce.Services.csproj", "src/ECommerce.Services/"]
COPY ["src/ECommerce.Data/ECommerce.Data.csproj", "src/ECommerce.Data/"]
# Restore dependencies
RUN dotnet restore "src/ECommerce.API/ECommerce.API.csproj"
# Copy everything else
COPY . .
# Build
WORKDIR "/src/src/ECommerce.API"
RUN dotnet build "ECommerce.API.csproj" -c Release -o /app/build
# Stage 3: Publish
FROM build AS publish
RUN dotnet publish "ECommerce.API.csproj" -c Release -o /app/publish
# Stage 4: Final
FROM base AS final
WORKDIR /app
# Create a non-root user
RUN groupadd -r appuser && useradd -r -g appuser appuser
RUN chown -R appuser:appuser /app
USER appuser
COPY --from=publish /app/publish .
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:80/health || exit 1
ENTRYPOINT ["dotnet", "ECommerce.API.dll"]
// Program.cs - Modern minimal API approach using ECommerce.API; using ECommerce.Data; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); // Add services to container builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // Database configuration with environment flexibility builder.Services.AddDbContext<ECommerceContext>(options => { var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); if (builder.Environment.IsProduction()) { options.UseSqlServer(connectionString, sqlOptions => sqlOptions.EnableRetryOnFailure()); } else { options.UseSqlServer(connectionString); } }); // Health checks builder.Services.AddHealthChecks() .AddDbContextCheck<ECommerceContext>(); var app = builder.Build(); // Configure pipeline if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.MapHealthChecks("/health"); app.Run();
# Multi-stage Dockerfile for ASP.NET Core
# Stage 1: Base
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
# Install curl for health checks
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
# Stage 2: Build
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
# Copy project files
COPY ["src/ECommerce.API/ECommerce.API.csproj", "src/ECommerce.API/"]
COPY ["src/ECommerce.Services/ECommerce.Services.csproj", "src/ECommerce.Services/"]
COPY ["src/ECommerce.Data/ECommerce.Data.csproj", "src/ECommerce.Data/"]
# Restore dependencies
RUN dotnet restore "src/ECommerce.API/ECommerce.API.csproj"
# Copy everything else
COPY . .
# Build
WORKDIR "/src/src/ECommerce.API"
RUN dotnet build "ECommerce.API.csproj" -c Release -o /app/build
# Stage 3: Publish
FROM build AS publish
RUN dotnet publish "ECommerce.API.csproj" -c Release -o /app/publish
# Stage 4: Final
FROM base AS final
WORKDIR /app
# Create a non-root user
RUN groupadd -r appuser && useradd -r -g appuser appuser
RUN chown -R appuser:appuser /app
USER appuser
COPY --from=publish /app/publish .
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:80/health || exit 1
ENTRYPOINT ["dotnet", "ECommerce.API.dll"]Environment-Specific Configurations
// appsettings.Production.json
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=sql-server;Database=ECommerce;User Id=sa;Password=${SA_PASSWORD};TrustServerCertificate=true;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://+:80"
      }
    }
  }
}
// appsettings.Production.json { "ConnectionStrings": { "DefaultConnection": "Server=sql-server;Database=ECommerce;User Id=sa;Password=${SA_PASSWORD};TrustServerCertificate=true;" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", "Kestrel": { "Endpoints": { "Http": { "Url": "http://+:80" } } } }
4. Multi-Stage Docker Builds
Advanced Optimization Techniques
# Ultra-optimized multi-stage build
# Stage 1: Base with security scanning
FROM mcr.microsoft.com/dotnet/aspnet:8.0@sha256:abc123... AS base
USER root
WORKDIR /app
# Security hardening
RUN apt-get update && \
    apt-get upgrade -y && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*
# Stage 2: Build with caching optimization
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
# Copy only project files for better layer caching
COPY ["Directory.Build.props", "./"]
COPY ["src/ECommerce.API/ECommerce.API.csproj", "src/ECommerce.API/"]
COPY ["src/ECommerce.Services/ECommerce.Services.csproj", "src/ECommerce.Services/"]
COPY ["src/ECommerce.Data/ECommerce.Data.csproj", "src/ECommerce.Data/"]
# Restore with no cache for deterministic builds
RUN dotnet restore "src/ECommerce.API/ECommerce.API.csproj" --no-cache
# Copy source code
COPY . .
# Build with optimization
WORKDIR "/src/src/ECommerce.API"
RUN dotnet build "ECommerce.API.csproj" -c Release -o /app/build \
    --no-restore \
    -p:ContinuousIntegrationBuild=true
# Stage 3: Test
FROM build AS test
WORKDIR "/src/tests"
RUN dotnet test --logger "trx" --results-directory /testresults
# Stage 4: Publish with trimming
FROM build AS publish
RUN dotnet publish "ECommerce.API.csproj" -c Release -o /app/publish \
    --no-build \
    -p:PublishReadyToRun=true \
    -p:PublishTrimmed=true \
    -p:TrimMode=link
# Stage 5: Final optimized image
FROM base AS final
WORKDIR /app
# Non-root user for security
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
RUN chown -R appuser:appgroup /app
USER appuser
COPY --from=publish /app/publish .
# Enhanced health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
    CMD curl -f http://localhost:80/health || exit 1
ENTRYPOINT ["dotnet", "ECommerce.API.dll"]
# Ultra-optimized multi-stage build
# Stage 1: Base with security scanning
FROM mcr.microsoft.com/dotnet/aspnet:8.0@sha256:abc123... AS base
USER root
WORKDIR /app
# Security hardening
RUN apt-get update && \
    apt-get upgrade -y && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*
# Stage 2: Build with caching optimization
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
# Copy only project files for better layer caching
COPY ["Directory.Build.props", "./"]
COPY ["src/ECommerce.API/ECommerce.API.csproj", "src/ECommerce.API/"]
COPY ["src/ECommerce.Services/ECommerce.Services.csproj", "src/ECommerce.Services/"]
COPY ["src/ECommerce.Data/ECommerce.Data.csproj", "src/ECommerce.Data/"]
# Restore with no cache for deterministic builds
RUN dotnet restore "src/ECommerce.API/ECommerce.API.csproj" --no-cache
# Copy source code
COPY . .
# Build with optimization
WORKDIR "/src/src/ECommerce.API"
RUN dotnet build "ECommerce.API.csproj" -c Release -o /app/build \
    --no-restore \
    -p:ContinuousIntegrationBuild=true
# Stage 3: Test
FROM build AS test
WORKDIR "/src/tests"
RUN dotnet test --logger "trx" --results-directory /testresults
# Stage 4: Publish with trimming
FROM build AS publish
RUN dotnet publish "ECommerce.API.csproj" -c Release -o /app/publish \
    --no-build \
    -p:PublishReadyToRun=true \
    -p:PublishTrimmed=true \
    -p:TrimMode=link
# Stage 5: Final optimized image
FROM base AS final
WORKDIR /app
# Non-root user for security
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
RUN chown -R appuser:appgroup /app
USER appuser
COPY --from=publish /app/publish .
# Enhanced health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
    CMD curl -f http://localhost:80/health || exit 1
ENTRYPOINT ["dotnet", "ECommerce.API.dll"]Build Arguments and Environment Variables
# Parameterized Dockerfile
ARG RUNTIME_IMAGE=mcr.microsoft.com/dotnet/aspnet:8.0
ARG SDK_IMAGE=mcr.microsoft.com/dotnet/sdk:8.0
ARG CONFIGURATION=Release
FROM ${RUNTIME_IMAGE} AS base
# ... base layer setup
FROM ${SDK_IMAGE} AS build
ARG CONFIGURATION
# ... build with ${CONFIGURATION}
# Build command with arguments
# docker build --build-arg CONFIGURATION=Debug -t myapp:debug .
# Parameterized Dockerfile
ARG RUNTIME_IMAGE=mcr.microsoft.com/dotnet/aspnet:8.0
ARG SDK_IMAGE=mcr.microsoft.com/dotnet/sdk:8.0
ARG CONFIGURATION=Release
FROM ${RUNTIME_IMAGE} AS base
# ... base layer setup
FROM ${SDK_IMAGE} AS build
ARG CONFIGURATION
# ... build with ${CONFIGURATION}
# Build command with arguments
# docker build --build-arg CONFIGURATION=Debug -t myapp:debug .5. Docker Compose for Development
Complete Development Environment
# docker-compose.yml - Full development stack
version: '3.8'
services:
  ecommerce.api:
    image: ecommerce-api:latest
    build:
      context: .
      dockerfile: Dockerfile
      target: build  # Use build stage for development
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ConnectionStrings__DefaultConnection=Server=sql-server;Database=ECommerce;User Id=sa;Password=YourPassword123!;TrustServerCertificate=true;
    ports:
      - "5000:80"
    volumes:
      - .:/src
      - ~/.nuget/packages:/root/.nuget/packages:ro
    depends_on:
      - sql-server
      - redis
    networks:
      - ecommerce-network
  sql-server:
    image: mcr.microsoft.com/mssql/server:2022-latest
    environment:
      SA_PASSWORD: "YourPassword123!"
      ACCEPT_EULA: "Y"
      MSSQL_PID: "Express"
    ports:
      - "1433:1433"
    volumes:
      - sql-data:/var/opt/mssql
    networks:
      - ecommerce-network
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data
    networks:
      - ecommerce-network
  seq:
    image: datalust/seq:latest
    environment:
      - ACCEPT_EULA=Y
    ports:
      - "5341:5341"
      - "8081:80"
    volumes:
      - seq-data:/data
    networks:
      - ecommerce-network
volumes:
  sql-data:
  redis-data:
  seq-data:
networks:
  ecommerce-network:
    driver: bridge
# docker-compose.yml - Full development stack version: '3.8' services: ecommerce.api: image: ecommerce-api:latest build: context: . dockerfile: Dockerfile target: build # Use build stage for development environment: - ASPNETCORE_ENVIRONMENT=Development - ConnectionStrings__DefaultConnection=Server=sql-server;Database=ECommerce;User Id=sa;Password=YourPassword123!;TrustServerCertificate=true; ports: - "5000:80" volumes: - .:/src - ~/.nuget/packages:/root/.nuget/packages:ro depends_on: - sql-server - redis networks: - ecommerce-network sql-server: image: mcr.microsoft.com/mssql/server:2022-latest environment: SA_PASSWORD: "YourPassword123!" ACCEPT_EULA: "Y" MSSQL_PID: "Express" ports: - "1433:1433" volumes: - sql-data:/var/opt/mssql networks: - ecommerce-network redis: image: redis:7-alpine ports: - "6379:6379" volumes: - redis-data:/data networks: - ecommerce-network seq: image: datalust/seq:latest environment: - ACCEPT_EULA=Y ports: - "5341:5341" - "8081:80" volumes: - seq-data:/data networks: - ecommerce-network volumes: sql-data: redis-data: seq-data: networks: ecommerce-network: driver: bridge
Development-Specific Dockerfile
# Dockerfile.dev - Development optimized
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS development
# Install tools for development
RUN dotnet tool install -g dotnet-ef
RUN dotnet tool install -g dotnet-watch
ENV PATH="$PATH:/root/.dotnet/tools"
WORKDIR /app
# Copy project files
COPY . .
# Expose ports
EXPOSE 80
EXPOSE 443
# Development entry point
CMD ["dotnet", "watch", "run", "--urls", "http://0.0.0.0:80"]
# Dockerfile.dev - Development optimized FROM mcr.microsoft.com/dotnet/sdk:8.0 AS development # Install tools for development RUN dotnet tool install -g dotnet-ef RUN dotnet tool install -g dotnet-watch ENV PATH="$PATH:/root/.dotnet/tools" WORKDIR /app # Copy project files COPY . . # Expose ports EXPOSE 80 EXPOSE 443 # Development entry point CMD ["dotnet", "watch", "run", "--urls", "http://0.0.0.0:80"]
Database Migration Strategy
// Database migrator service
public static class DatabaseMigrator
{
    public static async Task MigrateDatabaseAsync(this WebApplication app)
    {
        using var scope = app.Services.CreateScope();
        var services = scope.ServiceProvider;
        
        try
        {
            var context = services.GetRequiredService<ECommerceContext>();
            await context.Database.MigrateAsync();
            
            app.Logger.LogInformation("Database migrated successfully");
        }
        catch (Exception ex)
        {
            app.Logger.LogError(ex, "An error occurred while migrating the database");
            throw;
        }
    }
}
// In Program.cs
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
    await app.MigrateDatabaseAsync();
}
// Database migrator service public static class DatabaseMigrator { public static async Task MigrateDatabaseAsync(this WebApplication app) { using var scope = app.Services.CreateScope(); var services = scope.ServiceProvider; try { var context = services.GetRequiredService<ECommerceContext>(); await context.Database.MigrateAsync(); app.Logger.LogInformation("Database migrated successfully"); } catch (Exception ex) { app.Logger.LogError(ex, "An error occurred while migrating the database"); throw; } } } // In Program.cs var app = builder.Build(); if (app.Environment.IsDevelopment()) { await app.MigrateDatabaseAsync(); }
6. Kubernetes Core Concepts
Kubernetes Architecture Overview
# Understanding Kubernetes components
Kubernetes Cluster:
  Control Plane:
    - API Server: Frontend for Kubernetes
    - etcd: Key-value store for cluster data
    - Scheduler: Assigns pods to nodes
    - Controller Manager: Regulates cluster state
  Worker Nodes:
    - Kubelet: Agent running on each node
    - Container Runtime: Docker, containerd
    - Kube-proxy: Network proxy
# Understanding Kubernetes components Kubernetes Cluster: Control Plane: - API Server: Frontend for Kubernetes - etcd: Key-value store for cluster data - Scheduler: Assigns pods to nodes - Controller Manager: Regulates cluster state Worker Nodes: - Kubelet: Agent running on each node - Container Runtime: Docker, containerd - Kube-proxy: Network proxy
Essential Kubernetes Objects
# Pod - Smallest deployable unit
apiVersion: v1
kind: Pod
metadata:
  name: ecommerce-api-pod
  labels:
    app: ecommerce-api
    tier: backend
spec:
  containers:
  - name: ecommerce-api
    image: ecommerce-api:latest
    ports:
    - containerPort: 80
    env:
    - name: ASPNETCORE_ENVIRONMENT
      value: "Production"
# Service - Network abstraction
apiVersion: v1
kind: Service
metadata:
  name: ecommerce-api-service
spec:
  selector:
    app: ecommerce-api
  ports:
  - port: 80
    targetPort: 80
  type: LoadBalancer
# Deployment - Declarative updates
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ecommerce-api-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: ecommerce-api
  template:
    metadata:
      labels:
        app: ecommerce-api
    spec:
      containers:
      - name: ecommerce-api
        image: ecommerce-api:latest
        ports:
        - containerPort: 80
# Pod - Smallest deployable unit apiVersion: v1 kind: Pod metadata: name: ecommerce-api-pod labels: app: ecommerce-api tier: backend spec: containers: - name: ecommerce-api image: ecommerce-api:latest ports: - containerPort: 80 env: - name: ASPNETCORE_ENVIRONMENT value: "Production" # Service - Network abstraction apiVersion: v1 kind: Service metadata: name: ecommerce-api-service spec: selector: app: ecommerce-api ports: - port: 80 targetPort: 80 type: LoadBalancer # Deployment - Declarative updates apiVersion: apps/v1 kind: Deployment metadata: name: ecommerce-api-deployment spec: replicas: 3 selector: matchLabels: app: ecommerce-api template: metadata: labels: app: ecommerce-api spec: containers: - name: ecommerce-api image: ecommerce-api:latest ports: - containerPort: 80
Real-World E-Commerce Kubernetes Setup
# k8s/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: ecommerce-production
  labels:
    name: ecommerce-production
    environment: production
# k8s/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: ecommerce-config
  namespace: ecommerce-production
data:
  appsettings.json: |
    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*"
    }
# k8s/secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: ecommerce-secrets
  namespace: ecommerce-production
type: Opaque
data:
  connection-string: <base64-encoded-connection-string>
  api-key: <base64-encoded-api-key>
# k8s/namespace.yaml apiVersion: v1 kind: Namespace metadata: name: ecommerce-production labels: name: ecommerce-production environment: production # k8s/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: ecommerce-config namespace: ecommerce-production data: appsettings.json: | { "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" } # k8s/secret.yaml apiVersion: v1 kind: Secret metadata: name: ecommerce-secrets namespace: ecommerce-production type: Opaque data: connection-string: <base64-encoded-connection-string> api-key: <base64-encoded-api-key>
7. Kubernetes Deployment Strategies
Complete Deployment Configuration
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ecommerce-api
  namespace: ecommerce-production
  labels:
    app: ecommerce-api
    version: v1.0.0
spec:
  replicas: 3
  minReadySeconds: 30
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: ecommerce-api
  template:
    metadata:
      labels:
        app: ecommerce-api
        version: v1.0.0
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "80"
        prometheus.io/path: "/metrics"
    spec:
      containers:
      - name: ecommerce-api
        image: ecommerce-api:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
          name: http
        - containerPort: 443
          name: https
        env:
        - name: ASPNETCORE_ENVIRONMENT
          value: "Production"
        - name: ConnectionStrings__DefaultConnection
          valueFrom:
            secretKeyRef:
              name: ecommerce-secrets
              key: connection-string
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: 80
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /health/ready
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 1
        startupProbe:
          httpGet:
            path: /health/startup
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 10
          failureThreshold: 3
        securityContext:
          allowPrivilegeEscalation: false
          runAsNonRoot: true
          runAsUser: 1000
          capabilities:
            drop:
            - ALL
      restartPolicy: Always
      terminationGracePeriodSeconds: 60
# k8s/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: ecommerce-api namespace: ecommerce-production labels: app: ecommerce-api version: v1.0.0 spec: replicas: 3 minReadySeconds: 30 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 revisionHistoryLimit: 3 selector: matchLabels: app: ecommerce-api template: metadata: labels: app: ecommerce-api version: v1.0.0 annotations: prometheus.io/scrape: "true" prometheus.io/port: "80" prometheus.io/path: "/metrics" spec: containers: - name: ecommerce-api image: ecommerce-api:latest imagePullPolicy: IfNotPresent ports: - containerPort: 80 name: http - containerPort: 443 name: https env: - name: ASPNETCORE_ENVIRONMENT value: "Production" - name: ConnectionStrings__DefaultConnection valueFrom: secretKeyRef: name: ecommerce-secrets key: connection-string resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m" livenessProbe: httpGet: path: /health port: 80 initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /health/ready port: 80 initialDelaySeconds: 5 periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 1 startupProbe: httpGet: path: /health/startup port: 80 initialDelaySeconds: 10 periodSeconds: 10 failureThreshold: 3 securityContext: allowPrivilegeEscalation: false runAsNonRoot: true runAsUser: 1000 capabilities: drop: - ALL restartPolicy: Always terminationGracePeriodSeconds: 60
Service and Ingress Configuration
# k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: ecommerce-api-service
  namespace: ecommerce-production
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-internal: "false"
spec:
  selector:
    app: ecommerce-api
  ports:
  - name: http
    port: 80
    targetPort: 80
    protocol: TCP
  - name: https
    port: 443
    targetPort: 443
    protocol: TCP
  type: LoadBalancer
# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ecommerce-ingress
  namespace: ecommerce-production
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  tls:
  - hosts:
    - api.ecommerce.com
    secretName: ecommerce-tls
  rules:
  - host: api.ecommerce.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: ecommerce-api-service
            port:
              number: 80
# k8s/service.yaml apiVersion: v1 kind: Service metadata: name: ecommerce-api-service namespace: ecommerce-production annotations: service.beta.kubernetes.io/azure-load-balancer-internal: "false" spec: selector: app: ecommerce-api ports: - name: http port: 80 targetPort: 80 protocol: TCP - name: https port: 443 targetPort: 443 protocol: TCP type: LoadBalancer # k8s/ingress.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ecommerce-ingress namespace: ecommerce-production annotations: nginx.ingress.kubernetes.io/rewrite-target: / nginx.ingress.kubernetes.io/ssl-redirect: "true" cert-manager.io/cluster-issuer: "letsencrypt-prod" spec: tls: - hosts: - api.ecommerce.com secretName: ecommerce-tls rules: - host: api.ecommerce.com http: paths: - path: / pathType: Prefix backend: service: name: ecommerce-api-service port: number: 80
Horizontal Pod Autoscaler
# k8s/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: ecommerce-api-hpa
  namespace: ecommerce-production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: ecommerce-api
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
      - type: Percent
        value: 50
        periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 60
      policies:
      - type: Percent
        value: 100
        periodSeconds: 60
# k8s/hpa.yaml apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: ecommerce-api-hpa namespace: ecommerce-production spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: ecommerce-api minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80 behavior: scaleDown: stabilizationWindowSeconds: 300 policies: - type: Percent value: 50 periodSeconds: 60 scaleUp: stabilizationWindowSeconds: 60 policies: - type: Percent value: 100 periodSeconds: 60
8. Production-Grade Configuration
Advanced Health Checks
// Advanced health monitoring
public static class HealthCheckExtensions
{
    public static IHealthChecksBuilder AddProductionHealthChecks(
        this IServiceCollection services, 
        IConfiguration configuration)
    {
        return services.AddHealthChecks()
            .AddDbContextCheck<ECommerceContext>(
                name: "database",
                tags: new[] { "ready", "live" })
            .AddRedis(
                redisConnectionString: configuration.GetConnectionString("Redis"),
                name: "redis",
                tags: new[] { "ready", "live" })
            .AddUrlGroup(
                new Uri("https://api.paymentgateway.com/health"),
                name: "payment-gateway",
                tags: new[] { "ready" })
            .AddDiskStorageHealthCheck(s => 
                s.AddDrive("C:\\", 1024), 
                name: "storage",
                tags: new[] { "live" })
            .AddApplicationInsightsPublisher();
    }
}
// Custom health check for business logic
public class OrderProcessingHealthCheck : IHealthCheck
{
    private readonly ECommerceContext _context;
    public OrderProcessingHealthCheck(ECommerceContext context)
    {
        _context = context;
    }
    public async Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, 
        CancellationToken cancellationToken = default)
    {
        try
        {
            // Check if orders can be processed
            var recentOrders = await _context.Orders
                .Where(o => o.CreatedAt > DateTime.UtcNow.AddHours(-1))
                .CountAsync(cancellationToken);
            return recentOrders >= 0 
                ? HealthCheckResult.Healthy("Order processing is operational")
                : HealthCheckResult.Degraded("Order processing is experiencing issues");
        }
        catch (Exception ex)
        {
            return HealthCheckResult.Unhealthy("Order processing health check failed", ex);
        }
    }
}
// Advanced health monitoring public static class HealthCheckExtensions { public static IHealthChecksBuilder AddProductionHealthChecks( this IServiceCollection services, IConfiguration configuration) { return services.AddHealthChecks() .AddDbContextCheck<ECommerceContext>( name: "database", tags: new[] { "ready", "live" }) .AddRedis( redisConnectionString: configuration.GetConnectionString("Redis"), name: "redis", tags: new[] { "ready", "live" }) .AddUrlGroup( new Uri("https://api.paymentgateway.com/health"), name: "payment-gateway", tags: new[] { "ready" }) .AddDiskStorageHealthCheck(s => s.AddDrive("C:\\", 1024), name: "storage", tags: new[] { "live" }) .AddApplicationInsightsPublisher(); } } // Custom health check for business logic public class OrderProcessingHealthCheck : IHealthCheck { private readonly ECommerceContext _context; public OrderProcessingHealthCheck(ECommerceContext context) { _context = context; } public async Task<HealthCheckResult> CheckHealthAsync( HealthCheckContext context, CancellationToken cancellationToken = default) { try { // Check if orders can be processed var recentOrders = await _context.Orders .Where(o => o.CreatedAt > DateTime.UtcNow.AddHours(-1)) .CountAsync(cancellationToken); return recentOrders >= 0 ? HealthCheckResult.Healthy("Order processing is operational") : HealthCheckResult.Degraded("Order processing is experiencing issues"); } catch (Exception ex) { return HealthCheckResult.Unhealthy("Order processing health check failed", ex); } } }
Configuration Management
// Configuration builder with multiple sources
public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((context, config) =>
        {
            config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                  .AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", 
                              optional: true, reloadOnChange: true)
                  .AddEnvironmentVariables()
                  .AddUserSecrets<Program>(optional: true);
            if (context.HostingEnvironment.IsProduction())
            {
                config.AddAzureKeyVault(
                    "https://mykeyvault.vault.azure.net/",
                    new DefaultAzureCredential());
            }
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        })
        .UseSerilog((context, configuration) =>
        {
            configuration.ReadFrom.Configuration(context.Configuration);
        });
// Configuration builder with multiple sources public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((context, config) => { config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables() .AddUserSecrets<Program>(optional: true); if (context.HostingEnvironment.IsProduction()) { config.AddAzureKeyVault( "https://mykeyvault.vault.azure.net/", new DefaultAzureCredential()); } }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }) .UseSerilog((context, configuration) => { configuration.ReadFrom.Configuration(context.Configuration); });
Resilience and Circuit Breaker Patterns
// Polly resilience policies
public static class ResiliencePolicies
{
    public static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
    {
        return HttpPolicyExtensions
            .HandleTransientHttpError()
            .OrResult(msg => !msg.IsSuccessStatusCode)
            .WaitAndRetryAsync(
                retryCount: 3,
                sleepDurationProvider: retryAttempt => 
                    TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
                onRetry: (outcome, timespan, retryCount, context) =>
                {
                    var logger = context.GetLogger();
                    logger?.LogWarning(
                        "Retry {RetryCount} after {Delay}ms for {OperationKey}", 
                        retryCount, timespan.TotalMilliseconds, context.OperationKey);
                });
    }
    public static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
    {
        return HttpPolicyExtensions
            .HandleTransientHttpError()
            .CircuitBreakerAsync(
                handledEventsAllowedBeforeBreaking: 3,
                durationOfBreak: TimeSpan.FromSeconds(30),
                onBreak: (outcome, breakDelay, context) =>
                {
                    var logger = context.GetLogger();
                    logger?.LogError(
                        "Circuit breaker opened for {BreakDelay}ms", 
                        breakDelay.TotalMilliseconds);
                },
                onReset: (context) =>
                {
                    var logger = context.GetLogger();
                    logger?.LogInformation("Circuit breaker reset");
                });
    }
}
// Usage in service registration
services.AddHttpClient<IPaymentService, PaymentService>()
    .AddPolicyHandler(ResiliencePolicies.GetRetryPolicy())
    .AddPolicyHandler(ResiliencePolicies.GetCircuitBreakerPolicy());
// Polly resilience policies public static class ResiliencePolicies { public static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() { return HttpPolicyExtensions .HandleTransientHttpError() .OrResult(msg => !msg.IsSuccessStatusCode) .WaitAndRetryAsync( retryCount: 3, sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), onRetry: (outcome, timespan, retryCount, context) => { var logger = context.GetLogger(); logger?.LogWarning( "Retry {RetryCount} after {Delay}ms for {OperationKey}", retryCount, timespan.TotalMilliseconds, context.OperationKey); }); } public static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy() { return HttpPolicyExtensions .HandleTransientHttpError() .CircuitBreakerAsync( handledEventsAllowedBeforeBreaking: 3, durationOfBreak: TimeSpan.FromSeconds(30), onBreak: (outcome, breakDelay, context) => { var logger = context.GetLogger(); logger?.LogError( "Circuit breaker opened for {BreakDelay}ms", breakDelay.TotalMilliseconds); }, onReset: (context) => { var logger = context.GetLogger(); logger?.LogInformation("Circuit breaker reset"); }); } } // Usage in service registration services.AddHttpClient<IPaymentService, PaymentService>() .AddPolicyHandler(ResiliencePolicies.GetRetryPolicy()) .AddPolicyHandler(ResiliencePolicies.GetCircuitBreakerPolicy());
9. CI/CD Pipeline Implementation
GitHub Actions Pipeline
# .github/workflows/deploy.yml
name: Deploy to Kubernetes
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    
    - name: Setup .NET
      uses: actions/setup-dotnet@v3
      with:
        dotnet-version: 8.0.x
        
    - name: Restore dependencies
      run: dotnet restore
      
    - name: Build
      run: dotnet build --no-restore --configuration Release
      
    - name: Test
      run: dotnet test --no-build --verbosity normal --logger trx
  build-and-push:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Build Docker image
      run: |
        docker build . \
          --file Dockerfile \
          --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
          --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
          
    - name: Log into registry
      run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ${{ env.REGISTRY }} -u ${{ github.actor }} --password-stdin
      
    - name: Push Docker image
      run: |
        docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
        docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
  deploy:
    needs: build-and-push
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Deploy to Kubernetes
      uses: azure/k8s-deploy@v4
      with:
        namespace: ecommerce-production
        manifests: |
          k8s/namespace.yaml
          k8s/configmap.yaml
          k8s/secret.yaml
          k8s/deployment.yaml
          k8s/service.yaml
          k8s/ingress.yaml
          k8s/hpa.yaml
        images: |
          ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
        kubectl-version: 'latest'
        
    - name: Verify deployment
      run: |
        kubectl rollout status deployment/ecommerce-api -n ecommerce-production
        kubectl get pods -n ecommerce-production
# .github/workflows/deploy.yml name: Deploy to Kubernetes on: push: branches: [ main ] pull_request: branches: [ main ] env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup .NET uses: actions/setup-dotnet@v3 with: dotnet-version: 8.0.x - name: Restore dependencies run: dotnet restore - name: Build run: dotnet build --no-restore --configuration Release - name: Test run: dotnet test --no-build --verbosity normal --logger trx build-and-push: needs: test runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v3 - name: Build Docker image run: | docker build . \ --file Dockerfile \ --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \ --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} - name: Log into registry run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ${{ env.REGISTRY }} -u ${{ github.actor }} --password-stdin - name: Push Docker image run: | docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} deploy: needs: build-and-push runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Deploy to Kubernetes uses: azure/k8s-deploy@v4 with: namespace: ecommerce-production manifests: | k8s/namespace.yaml k8s/configmap.yaml k8s/secret.yaml k8s/deployment.yaml k8s/service.yaml k8s/ingress.yaml k8s/hpa.yaml images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} kubectl-version: 'latest' - name: Verify deployment run: | kubectl rollout status deployment/ecommerce-api -n ecommerce-production kubectl get pods -n ecommerce-production
Azure DevOps Pipeline
# azure-pipelines.yml
trigger:
  branches:
    include:
    - main
    - develop
variables:
  dockerRegistryServiceConnection: 'AzureContainerRegistry'
  imageRepository: 'ecommerceapi'
  containerRegistry: 'myacr.azurecr.io'
  dockerfilePath: '$(Build.SourcesDirectory)/Dockerfile'
  tag: '$(Build.BuildId)'
  
stages:
- stage: Build
  displayName: Build and test
  jobs:
  - job: Build
    displayName: Build
    pool:
      vmImage: 'ubuntu-latest'
      
    steps:
    - task: DotNetCoreCLI@2
      displayName: 'Restore dependencies'
      inputs:
        command: 'restore'
        
    - task: DotNetCoreCLI@2
      displayName: 'Build solution'
      inputs:
        command: 'build'
        arguments: '--no-restore --configuration Release'
        
    - task: DotNetCoreCLI@2
      displayName: 'Run tests'
      inputs:
        command: 'test'
        arguments: '--no-build --verbosity normal --logger trx'
        
    - task: Docker@2
      displayName: 'Build Docker image'
      inputs:
        command: 'build'
        repository: '$(imageRepository)'
        dockerfile: '$(dockerfilePath)'
        tags: |
          $(tag)
          latest
          
    - task: Docker@2
      displayName: 'Push Docker image'
      inputs:
        command: 'push'
        repository: '$(imageRepository)'
        tags: |
          $(tag)
          latest
- stage: DeployToStaging
  displayName: Deploy to staging
  dependsOn: Build
  condition: succeeded()
  
  jobs:
  - deployment: Deploy
    displayName: Deploy
    environment: 'staging'
    pool:
      vmImage: 'ubuntu-latest'
      
    strategy:
      runOnce:
        deploy:
          steps:
          - task: KubernetesManifest@0
            displayName: 'Deploy to Kubernetes'
            inputs:
              action: 'deploy'
              namespace: 'ecommerce-staging'
              manifests: |
                $(Build.SourcesDirectory)/k8s/**/*.yaml
              containers: |
                $(containerRegistry)/$(imageRepository):$(tag)
                
          - task: Kubernetes@1
            displayName: 'Verify deployment'
            inputs:
              command: 'rollout'
              arguments: 'status deployment/ecommerce-api -n ecommerce-staging'
# azure-pipelines.yml trigger: branches: include: - main - develop variables: dockerRegistryServiceConnection: 'AzureContainerRegistry' imageRepository: 'ecommerceapi' containerRegistry: 'myacr.azurecr.io' dockerfilePath: '$(Build.SourcesDirectory)/Dockerfile' tag: '$(Build.BuildId)' stages: - stage: Build displayName: Build and test jobs: - job: Build displayName: Build pool: vmImage: 'ubuntu-latest' steps: - task: DotNetCoreCLI@2 displayName: 'Restore dependencies' inputs: command: 'restore' - task: DotNetCoreCLI@2 displayName: 'Build solution' inputs: command: 'build' arguments: '--no-restore --configuration Release' - task: DotNetCoreCLI@2 displayName: 'Run tests' inputs: command: 'test' arguments: '--no-build --verbosity normal --logger trx' - task: Docker@2 displayName: 'Build Docker image' inputs: command: 'build' repository: '$(imageRepository)' dockerfile: '$(dockerfilePath)' tags: | $(tag) latest - task: Docker@2 displayName: 'Push Docker image' inputs: command: 'push' repository: '$(imageRepository)' tags: | $(tag) latest - stage: DeployToStaging displayName: Deploy to staging dependsOn: Build condition: succeeded() jobs: - deployment: Deploy displayName: Deploy environment: 'staging' pool: vmImage: 'ubuntu-latest' strategy: runOnce: deploy: steps: - task: KubernetesManifest@0 displayName: 'Deploy to Kubernetes' inputs: action: 'deploy' namespace: 'ecommerce-staging' manifests: | $(Build.SourcesDirectory)/k8s/**/*.yaml containers: | $(containerRegistry)/$(imageRepository):$(tag) - task: Kubernetes@1 displayName: 'Verify deployment' inputs: command: 'rollout' arguments: 'status deployment/ecommerce-api -n ecommerce-staging'
Database Migration in CI/CD
// Database migration job in Kubernetes
apiVersion: batch/v1
kind: Job
metadata:
  name: database-migration
  namespace: ecommerce-production
spec:
  template:
    spec:
      containers:
      - name: migrator
        image: ecommerce-api:latest
        command: ["dotnet", "ECommerce.API.dll", "migrate"]
        env:
        - name: ASPNETCORE_ENVIRONMENT
          value: "Production"
        - name: ConnectionStrings__DefaultConnection
          valueFrom:
            secretKeyRef:
              name: ecommerce-secrets
              key: connection-string
      restartPolicy: Never
  backoffLimit: 2
// Database migration job in Kubernetes apiVersion: batch/v1 kind: Job metadata: name: database-migration namespace: ecommerce-production spec: template: spec: containers: - name: migrator image: ecommerce-api:latest command: ["dotnet", "ECommerce.API.dll", "migrate"] env: - name: ASPNETCORE_ENVIRONMENT value: "Production" - name: ConnectionStrings__DefaultConnection valueFrom: secretKeyRef: name: ecommerce-secrets key: connection-string restartPolicy: Never backoffLimit: 2
10. Monitoring and Logging
Structured Logging with Serilog
// Program.cs with advanced logging
using Serilog;
using Serilog.Events;
using Serilog.Sinks.Elasticsearch;
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
    .MinimumLevel.Override("System", LogEventLevel.Warning)
    .Enrich.FromLogContext()
    .Enrich.WithProperty("Application", "ECommerce.API")
    .Enrich.WithMachineName()
    .Enrich.WithEnvironmentName()
    .WriteTo.Console(
        outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}")
    .WriteTo.File(
        "logs/ecommerce-.log",
        rollingInterval: RollingInterval.Day,
        retainedFileCountLimit: 7,
        outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
    .WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri("http://elasticsearch:9200"))
    {
        AutoRegisterTemplate = true,
        AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv7,
        IndexFormat = "ecommerce-logs-{0:yyyy.MM}",
        NumberOfShards = 2,
        NumberOfReplicas = 1
    })
    .CreateLogger();
try
{
    Log.Information("Starting web application");
    
    var builder = WebApplication.CreateBuilder(args);
    
    builder.Host.UseSerilog();
    
    // ... rest of configuration
    
    var app = builder.Build();
    
    // ... app configuration
    
    app.Run();
}
catch (Exception ex)
{
    Log.Fatal(ex, "Application terminated unexpectedly");
}
finally
{
    Log.CloseAndFlush();
}
// Program.cs with advanced logging using Serilog; using Serilog.Events; using Serilog.Sinks.Elasticsearch; Log.Logger = new LoggerConfiguration() .MinimumLevel.Information() .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) .MinimumLevel.Override("System", LogEventLevel.Warning) .Enrich.FromLogContext() .Enrich.WithProperty("Application", "ECommerce.API") .Enrich.WithMachineName() .Enrich.WithEnvironmentName() .WriteTo.Console( outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}") .WriteTo.File( "logs/ecommerce-.log", rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7, outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}") .WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri("http://elasticsearch:9200")) { AutoRegisterTemplate = true, AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv7, IndexFormat = "ecommerce-logs-{0:yyyy.MM}", NumberOfShards = 2, NumberOfReplicas = 1 }) .CreateLogger(); try { Log.Information("Starting web application"); var builder = WebApplication.CreateBuilder(args); builder.Host.UseSerilog(); // ... rest of configuration var app = builder.Build(); // ... app configuration app.Run(); } catch (Exception ex) { Log.Fatal(ex, "Application terminated unexpectedly"); } finally { Log.CloseAndFlush(); }
Application Insights Integration
// Advanced telemetry configuration
public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
    services.AddApplicationInsightsTelemetry(options =>
    {
        options.ConnectionString = configuration["ApplicationInsights:ConnectionString"];
        options.EnableAdaptiveSampling = false;
    });
    
    services.AddApplicationInsightsKubernetesEnricher();
    
    // Custom telemetry initializer
    services.AddSingleton<ITelemetryInitializer, CustomTelemetryInitializer>();
}
public class CustomTelemetryInitializer : ITelemetryInitializer
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    public CustomTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }
    public void Initialize(ITelemetry telemetry)
    {
        var requestTelemetry = telemetry as RequestTelemetry;
        if (requestTelemetry != null)
        {
            var context = _httpContextAccessor.HttpContext;
            if (context != null)
            {
                requestTelemetry.Properties["User"] = context.User.Identity?.Name;
                requestTelemetry.Properties["ClientIP"] = context.Connection.RemoteIpAddress?.ToString();
            }
        }
    }
}
// Advanced telemetry configuration public void ConfigureServices(IServiceCollection services, IConfiguration configuration) { services.AddApplicationInsightsTelemetry(options => { options.ConnectionString = configuration["ApplicationInsights:ConnectionString"]; options.EnableAdaptiveSampling = false; }); services.AddApplicationInsightsKubernetesEnricher(); // Custom telemetry initializer services.AddSingleton<ITelemetryInitializer, CustomTelemetryInitializer>(); } public class CustomTelemetryInitializer : ITelemetryInitializer { private readonly IHttpContextAccessor _httpContextAccessor; public CustomTelemetryInitializer(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public void Initialize(ITelemetry telemetry) { var requestTelemetry = telemetry as RequestTelemetry; if (requestTelemetry != null) { var context = _httpContextAccessor.HttpContext; if (context != null) { requestTelemetry.Properties["User"] = context.User.Identity?.Name; requestTelemetry.Properties["ClientIP"] = context.Connection.RemoteIpAddress?.ToString(); } } } }
Kubernetes Monitoring Stack
# k8s/monitoring.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-config
  namespace: monitoring
data:
  prometheus.yml: |
    global:
      scrape_interval: 15s
      evaluation_interval: 15s
    
    scrape_configs:
    - job_name: 'ecommerce-api'
      kubernetes_sd_configs:
      - role: endpoints
        namespaces:
          names:
          - ecommerce-production
      relabel_configs:
      - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
        action: keep
        regex: true
      - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
        action: replace
        target_label: __metrics_path__
        regex: (.+)
      - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
        action: replace
        regex: ([^:]+)(?::\d+)?;(\d+)
        replacement: $1:$2
        target_label: __address__
      - action: labelmap
        regex: __meta_kubernetes_service_label_(.+)
      - source_labels: [__meta_kubernetes_namespace]
        action: replace
        target_label: kubernetes_namespace
      - source_labels: [__meta_kubernetes_service_name]
        action: replace
        target_label: kubernetes_name
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: prometheus
  namespace: monitoring
spec:
  replicas: 1
  selector:
    matchLabels:
      app: prometheus
  template:
    metadata:
      labels:
        app: prometheus
    spec:
      containers:
      - name: prometheus
        image: prom/prometheus:latest
        ports:
        - containerPort: 9090
        volumeMounts:
        - name: prometheus-config
          mountPath: /etc/prometheus/
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "1Gi"
            cpu: "1000m"
      volumes:
      - name: prometheus-config
        configMap:
          name: prometheus-config
# k8s/monitoring.yaml apiVersion: v1 kind: ConfigMap metadata: name: prometheus-config namespace: monitoring data: prometheus.yml: | global: scrape_interval: 15s evaluation_interval: 15s scrape_configs: - job_name: 'ecommerce-api' kubernetes_sd_configs: - role: endpoints namespaces: names: - ecommerce-production relabel_configs: - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] action: keep regex: true - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] action: replace target_label: __metrics_path__ regex: (.+) - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] action: replace regex: ([^:]+)(?::\d+)?;(\d+) replacement: $1:$2 target_label: __address__ - action: labelmap regex: __meta_kubernetes_service_label_(.+) - source_labels: [__meta_kubernetes_namespace] action: replace target_label: kubernetes_namespace - source_labels: [__meta_kubernetes_service_name] action: replace target_label: kubernetes_name --- apiVersion: apps/v1 kind: Deployment metadata: name: prometheus namespace: monitoring spec: replicas: 1 selector: matchLabels: app: prometheus template: metadata: labels: app: prometheus spec: containers: - name: prometheus image: prom/prometheus:latest ports: - containerPort: 9090 volumeMounts: - name: prometheus-config mountPath: /etc/prometheus/ resources: requests: memory: "512Mi" cpu: "500m" limits: memory: "1Gi" cpu: "1000m" volumes: - name: prometheus-config configMap: name: prometheus-config
11. Security Best Practices
Security Context and Policies
# k8s/security.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: ecommerce-api-sa
  namespace: ecommerce-production
automountServiceAccountToken: false
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: ecommerce-production
  name: ecommerce-api-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]
- apiGroups: [""]
  resources: ["configmaps", "secrets"]
  verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ecommerce-api-rolebinding
  namespace: ecommerce-production
subjects:
- kind: ServiceAccount
  name: ecommerce-api-sa
  namespace: ecommerce-production
roleRef:
  kind: Role
  name: ecommerce-api-role
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: ecommerce-api-network-policy
  namespace: ecommerce-production
spec:
  podSelector:
    matchLabels:
      app: ecommerce-api
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: ingress-nginx
    ports:
    - protocol: TCP
      port: 80
    - protocol: TCP
      port: 443
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          name: ecommerce-production
    ports:
    - protocol: TCP
      port: 1433
    - protocol: TCP
      port: 6379
# k8s/security.yaml apiVersion: v1 kind: ServiceAccount metadata: name: ecommerce-api-sa namespace: ecommerce-production automountServiceAccountToken: false --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: ecommerce-production name: ecommerce-api-role rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list"] - apiGroups: [""] resources: ["configmaps", "secrets"] verbs: ["get"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: ecommerce-api-rolebinding namespace: ecommerce-production subjects: - kind: ServiceAccount name: ecommerce-api-sa namespace: ecommerce-production roleRef: kind: Role name: ecommerce-api-role apiGroup: rbac.authorization.k8s.io --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: ecommerce-api-network-policy namespace: ecommerce-production spec: podSelector: matchLabels: app: ecommerce-api policyTypes: - Ingress - Egress ingress: - from: - namespaceSelector: matchLabels: name: ingress-nginx ports: - protocol: TCP port: 80 - protocol: TCP port: 443 egress: - to: - namespaceSelector: matchLabels: name: ecommerce-production ports: - protocol: TCP port: 1433 - protocol: TCP port: 6379
Container Security
# Security-hardened Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
# Security updates
RUN apt-get update && \
    apt-get upgrade -y && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*
# Create non-root user
RUN groupadd -r appgroup && \
    useradd -r -g appgroup -s /bin/false appuser
WORKDIR /app
# Set secure permissions
RUN chown -R appuser:appgroup /app && \
    chmod -R 755 /app
USER appuser
# Copy application
COPY --from=publish /app/publish .
# Security headers via environment
ENV ASPNETCORE_URLS=http://+:80
ENV DOTNET_RUNNING_IN_CONTAINER=true
ENV COMPlus_EnableDiagnostics=0
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:80/health || exit 1
ENTRYPOINT ["dotnet", "ECommerce.API.dll"]
# Security-hardened Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
# Security updates
RUN apt-get update && \
    apt-get upgrade -y && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*
# Create non-root user
RUN groupadd -r appgroup && \
    useradd -r -g appgroup -s /bin/false appuser
WORKDIR /app
# Set secure permissions
RUN chown -R appuser:appgroup /app && \
    chmod -R 755 /app
USER appuser
# Copy application
COPY --from=publish /app/publish .
# Security headers via environment
ENV ASPNETCORE_URLS=http://+:80
ENV DOTNET_RUNNING_IN_CONTAINER=true
ENV COMPlus_EnableDiagnostics=0
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:80/health || exit 1
ENTRYPOINT ["dotnet", "ECommerce.API.dll"]Secret Management
// Secure configuration management
public static class SecurityExtensions
{
    public static IServiceCollection AddSecureConfiguration(
        this IServiceCollection services, 
        IConfiguration configuration)
    {
        // Azure Key Vault integration
        if (configuration.GetValue<bool>("UseKeyVault"))
        {
            var keyVaultEndpoint = configuration["KeyVault:Endpoint"];
            services.AddAzureKeyVault(keyVaultEndpoint);
        }
        // Database encryption
        services.AddDbContext<ECommerceContext>(options =>
        {
            options.UseSqlServer(
                configuration.GetConnectionString("DefaultConnection"),
                sqlOptions =>
                {
                    sqlOptions.EnableRetryOnFailure();
                    sqlOptions.CommandTimeout(30);
                });
        });
        // Secure HTTP clients
        services.AddHttpClient("SecureClient")
            .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
            {
                ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
                {
                    // Custom certificate validation
                    return errors == System.Net.Security.SslPolicyErrors.None;
                }
            });
        return services;
    }
}
// Secure configuration management public static class SecurityExtensions { public static IServiceCollection AddSecureConfiguration( this IServiceCollection services, IConfiguration configuration) { // Azure Key Vault integration if (configuration.GetValue<bool>("UseKeyVault")) { var keyVaultEndpoint = configuration["KeyVault:Endpoint"]; services.AddAzureKeyVault(keyVaultEndpoint); } // Database encryption services.AddDbContext<ECommerceContext>(options => { options.UseSqlServer( configuration.GetConnectionString("DefaultConnection"), sqlOptions => { sqlOptions.EnableRetryOnFailure(); sqlOptions.CommandTimeout(30); }); }); // Secure HTTP clients services.AddHttpClient("SecureClient") .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler { ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { // Custom certificate validation return errors == System.Net.Security.SslPolicyErrors.None; } }); return services; } }
12. Real-World Case Study
E-Commerce Platform Deployment
Scenario: Deploying a high-traffic e-commerce platform with 1 million+ products and 10,000+ concurrent users.
Architecture:
Production Stack: Frontend: - React SPA (CDN hosted) - Azure Front Door for global distribution Backend: - ASP.NET Core API (Kubernetes) - Redis Cluster for caching - SQL Server Always On Availability Groups Infrastructure: - Azure Kubernetes Service (AKS) - Azure Application Gateway - Azure Monitor + Application Insights
Performance Optimization
// Caching strategy
public class DistributedCacheService : ICacheService
{
    private readonly IDistributedCache _cache;
    private readonly ILogger<DistributedCacheService> _logger;
    public DistributedCacheService(IDistributedCache cache, ILogger<DistributedCacheService> logger)
    {
        _cache = cache;
        _logger = logger;
    }
    public async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> factory, TimeSpan? expiration = null)
    {
        var cachedData = await _cache.GetStringAsync(key);
        if (cachedData != null)
        {
            _logger.LogDebug("Cache hit for {Key}", key);
            return JsonSerializer.Deserialize<T>(cachedData);
        }
        _logger.LogDebug("Cache miss for {Key}", key);
        var data = await factory();
        
        var options = new DistributedCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = expiration ?? TimeSpan.FromMinutes(30)
        };
        
        await _cache.SetStringAsync(key, JsonSerializer.Serialize(data), options);
        return data;
    }
}
// Database performance
public class OptimizedProductRepository : IProductRepository
{
    private readonly ECommerceContext _context;
    public OptimizedProductRepository(ECommerceContext context)
    {
        _context = context;
    }
    public async Task<List<Product>> GetFeaturedProductsAsync(int count)
    {
        return await _context.Products
            .Where(p => p.IsFeatured && p.IsActive)
            .OrderByDescending(p => p.CreatedAt)
            .Take(count)
            .AsNoTracking() // Read-only optimization
            .ToListAsync();
    }
    public async Task<Product> GetProductWithDetailsAsync(int productId)
    {
        return await _context.Products
            .Include(p => p.Category)
            .Include(p => p.Inventory)
            .Include(p => p.Reviews)
            .AsSplitQuery() // Performance optimization for multiple includes
            .FirstOrDefaultAsync(p => p.Id == productId);
    }
}
// Caching strategy public class DistributedCacheService : ICacheService { private readonly IDistributedCache _cache; private readonly ILogger<DistributedCacheService> _logger; public DistributedCacheService(IDistributedCache cache, ILogger<DistributedCacheService> logger) { _cache = cache; _logger = logger; } public async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> factory, TimeSpan? expiration = null) { var cachedData = await _cache.GetStringAsync(key); if (cachedData != null) { _logger.LogDebug("Cache hit for {Key}", key); return JsonSerializer.Deserialize<T>(cachedData); } _logger.LogDebug("Cache miss for {Key}", key); var data = await factory(); var options = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = expiration ?? TimeSpan.FromMinutes(30) }; await _cache.SetStringAsync(key, JsonSerializer.Serialize(data), options); return data; } } // Database performance public class OptimizedProductRepository : IProductRepository { private readonly ECommerceContext _context; public OptimizedProductRepository(ECommerceContext context) { _context = context; } public async Task<List<Product>> GetFeaturedProductsAsync(int count) { return await _context.Products .Where(p => p.IsFeatured && p.IsActive) .OrderByDescending(p => p.CreatedAt) .Take(count) .AsNoTracking() // Read-only optimization .ToListAsync(); } public async Task<Product> GetProductWithDetailsAsync(int productId) { return await _context.Products .Include(p => p.Category) .Include(p => p.Inventory) .Include(p => p.Reviews) .AsSplitQuery() // Performance optimization for multiple includes .FirstOrDefaultAsync(p => p.Id == productId); } }
Disaster Recovery Plan
# k8s/backup.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: database-backup
  namespace: ecommerce-production
spec:
  schedule: "0 2 * * *" # Daily at 2 AM
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: backup
            image: mcr.microsoft.com/mssql-tools:latest
            command:
            - /bin/bash
            - -c
            - |
              /opt/mssql-tools/bin/sqlcmd -S $(DB_SERVER) -U $(DB_USER) -P $(DB_PASSWORD) \
              -Q "BACKUP DATABASE [ECommerce] TO DISK = '/backup/ecommerce_$(date +%Y%m%d_%H%M%S).bak'"
            volumeMounts:
            - name: backup-volume
              mountPath: /backup
            env:
            - name: DB_SERVER
              valueFrom:
                secretKeyRef:
                  name: ecommerce-secrets
                  key: db-server
            - name: DB_USER
              valueFrom:
                secretKeyRef:
                  name: ecommerce-secrets
                  key: db-user
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: ecommerce-secrets
                  key: db-password
          volumes:
          - name: backup-volume
            persistentVolumeClaim:
              claimName: backup-pvc
          restartPolicy: OnFailure
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: backup-pvc
  namespace: ecommerce-production
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 100Gi
# k8s/backup.yaml apiVersion: batch/v1 kind: CronJob metadata: name: database-backup namespace: ecommerce-production spec: schedule: "0 2 * * *" # Daily at 2 AM jobTemplate: spec: template: spec: containers: - name: backup image: mcr.microsoft.com/mssql-tools:latest command: - /bin/bash - -c - | /opt/mssql-tools/bin/sqlcmd -S $(DB_SERVER) -U $(DB_USER) -P $(DB_PASSWORD) \ -Q "BACKUP DATABASE [ECommerce] TO DISK = '/backup/ecommerce_$(date +%Y%m%d_%H%M%S).bak'" volumeMounts: - name: backup-volume mountPath: /backup env: - name: DB_SERVER valueFrom: secretKeyRef: name: ecommerce-secrets key: db-server - name: DB_USER valueFrom: secretKeyRef: name: ecommerce-secrets key: db-user - name: DB_PASSWORD valueFrom: secretKeyRef: name: ecommerce-secrets key: db-password volumes: - name: backup-volume persistentVolumeClaim: claimName: backup-pvc restartPolicy: OnFailure --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: backup-pvc namespace: ecommerce-production spec: accessModes: - ReadWriteOnce resources: requests: storage: 100Gi
Final Deployment Checklist
# Production Deployment Checklist
## Pre-Deployment
- [ ] Security scanning completed
- [ ] Performance testing passed
- [ ] Database migrations tested
- [ ] Rollback plan documented
- [ ] Team communication sent
## Deployment
- [ ] Blue-green deployment configured
- [ ] Health checks passing
- [ ] Monitoring dashboards updated
- [ ] Log aggregation working
- [ ] Alert rules configured
## Post-Deployment
- [ ] Smoke tests completed
- [ ] Performance metrics verified
- [ ] Error rate monitored
- [ ] User feedback collected
- [ ] Documentation updated
# Production Deployment Checklist ## Pre-Deployment - [ ] Security scanning completed - [ ] Performance testing passed - [ ] Database migrations tested - [ ] Rollback plan documented - [ ] Team communication sent ## Deployment - [ ] Blue-green deployment configured - [ ] Health checks passing - [ ] Monitoring dashboards updated - [ ] Log aggregation working - [ ] Alert rules configured ## Post-Deployment - [ ] Smoke tests completed - [ ] Performance metrics verified - [ ] Error rate monitored - [ ] User feedback collected - [ ] Documentation updated
This comprehensive guide covers the entire journey from local Docker development to production Kubernetes deployment for ASP.NET Core applications. The real-world examples, complete code samples, and production best practices provide a solid foundation for mastering cloud-native deployment strategies.
Powered By: FreeLearning365.com
.png)
0 Comments
thanks for your comments!