# Docker Utveckling djupdykning: Från grunderna till avancerad .NET Containerization

<datetime class="hidden">2025-11-09T14:00</datetime>

<!--category-- Docker, .NET, DevOps, Containers -->
## Inledning

Docker har i grunden förändrat hur vi bygger, skeppar och kör applikationer.

Det som började som ett enkelt containeriseringsverktyg har utvecklats till ett komplett ekosystem för modern applikationsutveckling och installation.

1. **[Detta är den fjärde och mest omfattande artikeln i min Docker-serie för .NET-utvecklare.](/dockercompose)**Om du är ny i Docker, kanske du vill börja med:
2. **[Docker komposera](/dockercomposedevdeps)**- Komma igång med grundläggande multi-container setups (2024 juli)
3. **[Utvecklingsberoenden med Docker Compose](/imagesharpwithdocker)**- Upprätta lokala dev miljöer (2024 augusti)

ImageSharp med Docker

- **- Lösa volymtillståndsfrågor (2024 augusti)**I detta djupa dyk, ska vi bygga på dessa fundament för att utforska:
- **Produktionsklara Docker Compose**: Själva stacken som kör denna blogg
- **Självvärdighet på begränsade resurser**: Praktiska optimeringstekniker för budget VPS-installationer
- **Stöd för GPU**: Köra ML arbetsbelastning i behållare
- **Byggnader för flera arkitekturer**: Stöd för ARM64 och AMD64
- **.NET 9 behållare funktioner**: Inbyggd container publicering utan Dockerfiles

> .NET-spiran

: Den moderna .NET tillvägagångssätt för container orkestrering

[TOC]

## OBS: Detta är en del av mina experiment med AI / ett sätt att spendera $ 1000 Claude Code Web krediter.

### Jag har matat detta en BUNCH av papper, min förståelse, frågor jag var tvungen att generera denna artikel.

Det är kul och fyller en lucka jag inte har sett fyllas någon annanstans.

Oavsett om du distribuerar en enkel webbapp eller iscensätter en komplex mikroservicearkitektur med GPU-accelererade maskininlärningsmodeller, tar denna guide dig från Docker grunderna till produktionsklara containeriserade applikationer - med verkliga exempel från att köra mestadels lucid.com.

- **Docker Fundamental: Förstå containrar**Vad är Docker egentligen?
- **I sin kärna är Docker en containeriseringsplattform som paketerar din applikation och alla dess beroenden till en standardiserad enhet som kallas en behållare.**Till skillnad från virtuella maskiner som virtualiserar hela operativsystem delar behållare värddatorns OS-kärna samtidigt som isolerade användarutrymmen bibehålls.

### Tänk på det så här:

```bash
# The classic developer problem
"It works on my machine!" 

# The container solution
"Ship your machine!" 
```

Virtuella maskiner

1. **: Varje VM kör en full OS stack (Linux-kärna, systembibliotek, etc.) - tung och långsam att starta**Behållare
2. **: Dela värdkärnan, paket endast programkod och beroenden - lätt och snabbt**Varför containrar är viktiga för utvecklare
3. **Containrar löser flera kritiska problem:**Miljökonsistens
4. **: Utveckling, testning och produktionsmiljöer är identiska**Isolering av beroendeförhållanden
5. **: Inga fler "DLL hell" eller motstridiga biblioteksversioner**Reproducerbara byggnader

### : Samma indata = samma utdata, varje gång

#### Snabb utbyggnad

```bash
# An image is a template (like a class in OOP)
docker pull mcr.microsoft.com/dotnet/aspnet:9.0

# A container is a running instance (like an object)
docker run -d -p 8080:8080 myapp:latest
```

**: Starta behållare på några sekunder, inte minuter**Resurseffektivitet

```dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:9.0      # Layer 1: Base OS + .NET runtime
WORKDIR /app                                   # Layer 2: Directory structure
COPY *.dll ./                                  # Layer 3: Application files
ENTRYPOINT ["dotnet", "MyApp.dll"]            # Layer 4: Startup command
```

: Kör dussintals containrar på en enda värd

- **Väsentliga dockningskoncept**Bilder vs Behållare
- **Bilder**är oföränderliga, skiktade filsystem.
- **Varje instruktion i en Dockerfil skapar ett nytt lager:**Denna skiktning är kraftfull:

#### Caching

: Oförändrade lager återanvänds, påskyndar byggen

```dockerfile
# Multi-stage build: separates build environment from runtime
# Stage 1: Build
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src

# Copy only csproj files first (better layer caching)
COPY ["MyApp/MyApp.csproj", "MyApp/"]
COPY ["MyApp.Core/MyApp.Core.csproj", "MyApp.Core/"]

# Restore dependencies (cached unless csproj changes)
RUN dotnet restore "MyApp/MyApp.csproj"

# Copy everything else
COPY . .

# Build the application
WORKDIR "/src/MyApp"
RUN dotnet build "MyApp.csproj" -c Release -o /app/build

# Stage 2: Publish
FROM build AS publish
RUN dotnet publish "MyApp.csproj" -c Release -o /app/publish /p:UseAppHost=false

# Stage 3: Final runtime image
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS final
WORKDIR /app

# Create non-root user for security
RUN addgroup --gid 1001 appuser && \
    adduser --uid 1001 --gid 1001 --disabled-password --gecos "" appuser

# Copy published output from publish stage
COPY --from=publish /app/publish .

# Switch to non-root user
USER appuser

# Expose port (documentation only, doesn't actually publish)
EXPOSE 8080

# Set environment variables
ENV ASPNETCORE_URLS=http://+:8080
ENV ASPNETCORE_ENVIRONMENT=Production

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:8080/health || exit 1

ENTRYPOINT ["dotnet", "MyApp.dll"]
```

**Delning**

1. **: Flera bilder kan dela baslager**Effektivitet
2. **: Endast ändrade lager behöver laddas ner/laddas upp**Dockerfile bästa praxis
3. **Här är en produktionsklar .NET Dockerfile med kommentarer:**Följande huvudprinciper illustrerades:
4. **Flerstegsbyggen**: Separata bygg-/publicera steg minska den slutliga bildstorleken dramatiskt
5. **Lageroptimering**: Kopiera beroendefiler innan källkod för bättre cachelagring

#### Säkerhet

```bash
# Build the image
docker build -t myapp:1.0.0 -t myapp:latest .

# Run with common options
docker run -d \
  --name myapp \
  -p 8080:8080 \
  -e ConnectionStrings__DefaultConnection="Server=db;Database=myapp" \
  -v /data/logs:/app/logs \
  --restart unless-stopped \
  myapp:latest

# View logs
docker logs -f myapp

# Execute commands inside running container
docker exec -it myapp /bin/bash

# Stop and remove
docker stop myapp
docker rm myapp
```

## : Kör som icke-root-användare

Hälsokontroller

### : Container orkestratorer kan övervaka applikationens hälsa

Explicit miljö

- : Ställ in förvalda produktioner
- Byggande och drift
- Docker Komposit: Multi-Container Orkestrering
- Docker Compose låter dig definiera och köra multi-container program.
- Istället för att hantera behållare individuellt, beskriver du hela din applikation stack i en YAML-fil.

Varför skrev dockan?`docker run`Betrakta en typisk .NET webbapplikation:

### Webbappen ASP.NET Core

PostgreSQL- databas**Redis- cacheName`docker-compose.yml`**Seq för loggning

```yaml
services:
  # Main ASP.NET Core application
  mostlylucid:
    image: scottgal/mostlylucid:latest
    restart: always
    healthcheck:
      test: [ "CMD", "curl", "-f -K", "https://mostlylucid:7240/healthy" ]
      interval: 30s
      timeout: 10s
      retries: 5
    labels:
      - "com.centurylinklabs.watchtower.enable=true"
    env_file:
      - .env
    environment:
      - Auth__GoogleClientId=${AUTH_GOOGLECLIENTID}
      - Auth__GoogleClientSecret=${AUTH_GOOGLECLIENTSECRET}
      - Auth__AdminUserGoogleId=${AUTH_ADMINUSERGOOGLEID}
      - SmtpSettings__UserName=${SMTPSETTINGS_USERNAME}
      - SmtpSettings__Password=${SMTPSETTINGS_PASSWORD}
      - Analytics__UmamiPath=${ANALYTICS_UMAMIPATH}
      - Analytics__WebsiteId=${ANALYTICS_WEBSITEID}
      - ConnectionStrings__DefaultConnection=${POSTGRES_CONNECTIONSTRING}
      - TranslateService__ServiceIPs=${EASYNMT_IPS}
      - Serilog__WriteTo__0__Args__apiKey=${SEQ_API_KEY}
      - Markdown__MarkdownPath=${MARKDOWN_MARKDOWNPATH}
    volumes:
      - /mnt/imagecache:/app/wwwroot/cache
      - /mnt/logs:/app/logs
      - /mnt/markdown:/app/markdown
      - ./mostlylucid.pfx:/app/mostlylucid.pfx
      - /mnt/articleimages:/app/wwwroot/articleimages
      - /mnt/mostlylucid/uploads:/app/wwwroot/uploads
    networks:
      - app_network
    depends_on:
      - db

  # PostgreSQL database
  db:
    image: postgres:16-alpine
    ports:
      - 5266:5432  # Custom external port to avoid conflicts
    env_file:
      - .env
    networks:
      - app_network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
      interval: 5s
      timeout: 5s
      retries: 5
    volumes:
      - /mnt/umami/postgres:/var/lib/postgresql/data
    restart: always

  # Cloudflare tunnel for secure external access
  cloudflared:
    image: cloudflare/cloudflared:latest
    command: tunnel --no-autoupdate run --token ${CLOUDFLARED_TOKEN}
    env_file:
      - .env
    restart: always
    networks:
      - app_network

  # Umami analytics
  umami:
    image: ghcr.io/umami-software/umami:postgresql-latest
    env_file: .env
    environment:
      DATABASE_URL: ${DATABASE_URL}
      DATABASE_TYPE: ${DATABASE_TYPE}
      HASH_SALT: ${HASH_SALT}
      APP_SECRET: ${APP_SECRET}
      TRACKER_SCRIPT_NAME: getinfo
      API_COLLECT_ENDPOINT: all
    depends_on:
      - db
    labels:
      - "com.centurylinklabs.watchtower.enable=true"
    networks:
      - app_network
    restart: always

  # Translation service (CPU-limited for resource management)
  easynmt:
    image: easynmt/api:2.0.2-cpu
    volumes:
      - /mnt/easynmt:/cache/
    deploy:
      resources:
        limits:
          cpus: "4.0"  # Prevent translation service from consuming all CPU
    networks:
      - app_network

  # Caddy reverse proxy with automatic HTTPS
  caddy:
    image: caddy:latest
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - app_network
    restart: always

  # Seq centralized logging
  seq:
    image: datalust/seq
    container_name: seq
    restart: unless-stopped
    environment:
      ACCEPT_EULA: "Y"
      SEQ_FIRSTRUN_ADMINPASSWORDHASH: ${SEQ_DEFAULT_HASH}
    volumes:
      - /mnt/seq:/data
    networks:
      - app_network

  # Prometheus metrics collection
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    volumes:
      - prometheus-data:/prometheus
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
    labels:
      - "com.centurylinklabs.watchtower.enable=true"
    networks:
      - app_network

  # Grafana visualization
  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    labels:
      - "com.centurylinklabs.watchtower.enable=true"
    volumes:
      - grafana-data:/var/lib/grafana
    networks:
      - app_network
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}

  # Host metrics exporter
  node_exporter:
    image: quay.io/prometheus/node-exporter:latest
    container_name: node_exporter
    command:
      - '--path.rootfs=/host'
    networks:
      - app_network
    restart: unless-stopped
    volumes:
      - '/:/host:ro,rslave'

  # Automatic container updates
  watchtower:
    image: containrrr/watchtower
    container_name: watchtower
    restart: always
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - WATCHTOWER_CLEANUP=true
      - WATCHTOWER_LABEL_ENABLE=true
    command: --interval 300  # Check every 5 minutes

volumes:
  grafana-data:
  caddy_data:
  caddy_config:
  prometheus-data:

networks:
  app_network:
    driver: bridge
```

**Kanske en bakgrundsarbetartjänst**

1. **Hantera dessa individuellt med**kommandon blir otympliga.`app_network`Docker Compose löser det här.
2. **Komplett Real-World Exempel: Produktion Blogg Plattform**Här är den.`/mnt/*`Faktisk produktion
3. **som driver just denna webbplats (mestalylucid.com):**Nyckelproduktionsmönster:
4. **Ett enda nätverk**: Alla tjänster på
5. **för enkelhetens skull**Bindfästen
6. **: Värdvägar (**) för ihållande data du behöver för att säkerhetskopiera / komma åt
7. **Namngivna volymer**: Docker hanterad lagring för data du inte behöver direkt tillgång till`.env`Vakttornets etiketter

### : Endast uppdateringstjänster som uttryckligen är märkta för automatisk uppdatering

#### Resursgränser

```yaml
services:
  web:
    depends_on:
      db:
        condition: service_healthy  # Wait for health check
      redis:
        condition: service_started  # Just wait for start
```

: CPU begränsningar på översättningstjänst förhindra resurs svält`condition: service_healthy`Extern hamnkartläggning

#### : PostgreSQL på 5266 i stället för 5432 för att undvika konflikter med andra fall

```bash
# .env file (never commit to git!)
DB_PASSWORD=super_secret_password
SMTP_PASSWORD=another_secret
```

```yaml
services:
  web:
    environment:
      - DB_PASSWORD=${DB_PASSWORD}  # From .env file
      - STATIC_VALUE=production     # Hardcoded
    env_file:
      - .env                        # Load entire file
```

Miljöfiler

#### : Hemligheter i

```yaml
services:
  db:
    volumes:
      # Named volume (managed by Docker)
      - postgres_data:/var/lib/postgresql/data

  web:
    volumes:
      # Bind mount (maps host directory to container)
      - ./data/markdown:/app/Markdown
      - ./logs:/app/logs
```

**fil (aldrig förpliktigad till git)**:

- Docker komposerar viktiga funktioner
- Tjänsteberoenden
- Docker Komposiera orkestertes startordning.
- och

**kräver att databasen hälsokontroll passera innan du startar webbappen.**:

- Miljövariabler och hemligheter
- För produktionshemligheter, använd Docker Secrets eller externa hemliga chefer (AWS Secrets Manager, Azure Key Vault, HashiCorp Vault).
- Namngivna volymer vs Bind Mounts

#### Namngivna volymer

```yaml
networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

services:
  web:
    networks:
      - frontend
      - backend

  db:
    networks:
      - backend  # Not exposed to frontend
```

Hanterad av Docker

#### Persist data över behållare startas om

```yaml
services:
  db:
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
```

Kan säkerhetskopieras/återställs med Docker-kommandon

- Plattformskompatibel
- Bindfästen
- Direkt mappning till värdfilsystem

### Användbar för utveckling (live code reloading)

```bash
# Start all services (detached)
docker-compose up -d

# Start specific services
docker-compose up -d web db

# View logs (all services)
docker-compose logs -f

# View logs (specific service)
docker-compose logs -f web

# Stop services (containers remain)
docker-compose stop

# Stop and remove containers
docker-compose down

# Stop, remove containers, and remove volumes
docker-compose down -v

# Rebuild and restart
docker-compose up -d --build

# Scale a service
docker-compose up -d --scale worker=3

# Execute command in running service
docker-compose exec web /bin/bash

# Run one-off command
docker-compose run --rm web dotnet ef database update
```

### Inställningsfiler, loggar, uppladdningar

Nätverk

**Nätverken är isolerade.**Här är databasen endast tillgänglig för gränssnittstjänster, inte direkt exponerad.

```yaml
services:
  web:
    build: .
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
```

**Hälsokontroller**Hälsokontroller gör det möjligt för Docker att

```yaml
services:
  web:
    volumes:
      - .:/app  # Live code reloading
    ports:
      - "5000:8080"
```

**Bestäm om en behållare faktiskt är klar (inte bara påbörjad)**Starta om ohälsosamma behållare

```yaml
services:
  web:
    image: registry.example.com/myapp:${VERSION}
    restart: always
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '2'
          memory: 2G
```

```bash
# Development (base + override)
docker-compose up -d

# Production
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
```

## Ge status till orkestratorer (Kubernetes, Docker Swarm)

Vanliga Docker komposera kommandon

### Utveckling mot produktion komposerar filer

```bash
# Install NVIDIA Container Toolkit (Ubuntu/Debian)
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
  sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit

# Configure Docker daemon
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

# Test GPU access
docker run --rm --gpus all nvidia/cuda:12.6.0-base-ubuntu24.04 nvidia-smi
```

### Separata problem med flera komponera filer:

```dockerfile
# Use NVIDIA CUDA base image
FROM nvidia/cuda:12.6.0-cudnn-runtime-ubuntu24.04

# Install Python
RUN apt-get update && apt-get install -y \
    python3.12 \
    python3-pip \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Install PyTorch with CUDA support
COPY requirements.txt .
RUN pip3 install --no-cache-dir torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124

# Copy application
COPY . .

# Test GPU on container start
RUN python3 -c "import torch; print(f'CUDA available: {torch.cuda.is_available()}'); print(f'GPU: {torch.cuda.get_device_name(0) if torch.cuda.is_available() else \"None\"}')"

ENTRYPOINT ["python3", "train.py"]
```

### docker-kompose.yml

```bash
# Run with all GPUs
docker run --gpus all myapp:gpu

# Run with specific GPUs
docker run --gpus '"device=0,2"' myapp:gpu

# Run with GPU memory limits
docker run --gpus all --memory=16g myapp:gpu
```

### (grundnivå):

```yaml
services:
  ml-trainer:
    build:
      context: .
      dockerfile: Dockerfile.gpu
    image: myapp:gpu
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all  # or specific count: 1, 2, etc.
              capabilities: [gpu]
    volumes:
      - ./models:/app/models
      - ./data:/app/data
    environment:
      - NVIDIA_VISIBLE_DEVICES=all
      - CUDA_VISIBLE_DEVICES=0,1  # Use GPUs 0 and 1
```

### docker-compose.override.yml

(utveckling – automatisk sammanfogning):[docker-compose.prod.yml](https://github.com/scottgal/mostlylucid-nmt)(produktion):

GPU-stöd i Docker: påskynda ML Arbetsbelastningar

- **Maskininlärning, vetenskaplig databehandling och videobehandlingstillämpningar kräver ofta GPU-acceleration.**Docker stöder NVIDIA GPUs genom NVIDIA Container Toolkit.
- **Ställa in NVIDIA Container Toolkit**Dockerfil för GPU-accelererad Python/PyTorch-applikation
- **Köra GPU-containrar**GPU i Docker komposera
- **Real-World Exempel: Översättningstjänst med GPU och CPU Bygger**Här är ett riktigt produktionsexempel från

#### Mest lucid-nmt

```yaml
services:
  translation:
    image: scottgal/mostlylucid-nmt:gpu
    container_name: translation-gpu
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]
    environment:
      - MODEL_FAMILY=opus-mt
      - FALLBACK_MODELS=mbart50,m2m100
      - CUDA_VISIBLE_DEVICES=0
      - LOG_LEVEL=info
    volumes:
      - model_cache:/app/cache  # Persistent model storage
    ports:
      - "8888:8888"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8888/health"]
      interval: 30s
      timeout: 10s
      retries: 3

volumes:
  model_cache:
```

#### , en neural maskin översättning tjänst jag byggt som driver automatisk översättning på den här bloggen.

Projektet visar följande:

```yaml
services:
  translation:
    image: scottgal/mostlylucid-nmt:cpu
    container_name: translation-cpu
    environment:
      - MODEL_FAMILY=opus-mt
      - FALLBACK_MODELS=mbart50,m2m100
    volumes:
      - model_cache:/app/cache
    ports:
      - "8888:8888"
    restart: unless-stopped

volumes:
  model_cache:
```

**GPU- och CPU-varianter**

- `scottgal/mostlylucid-nmt:gpu`- Samma kodbas, olika basbilder
- `scottgal/mostlylucid-nmt:cpu`Byggnader för flera arkitekturer
- `scottgal/mostlylucid-nmt:gpu-min`- Stöder AMD64 och ARM64
- `scottgal/mostlylucid-nmt:cpu-min`Optimerade Docker-bilder

**- Både fullständiga och minimala varianter**

- **Produktionsfärdig**- Hälsokontroller, volympersistens, korrekt loggning
- **GPU-accelererad översättningstjänst**Endast alternativ för processor
- **För miljöer utan GPU, samma tjänst körs på CPU:**Tillgängliga bildvarianter:
- **- CUDA 12.6 med stöd för PyTorch GPU (~5GB)**- Endast processor, mindre fotavtryck (~2.5GB)
- **- Minimal GPU-bygge, inga förladdade modeller (~4GB)**: `/health`- Minimal CPU-bygge (~1.5GB)`/ready`Huvuddrag:
- **GPU-acceleration**: 10-15x snabbare översättning med CUDA

Modell Ladda ner automatiskt[: Nedladdningar översättningsmodeller on-demand](https://github.com/scottgal/mostlylucid-nmt)Stöd för fallskärmshoppning

## : Tries Opus-MT → mBART50 → M2M100 för maximal språktäckning

Volym Persistens

### : Cache modeller över behållaren startas om

```bash
# Problem: Image built on M1 Mac won't run on Linux server
docker build -t myapp:latest .  # Builds for ARM64
docker push myapp:latest
# Server tries to run it... error: "exec format error"

# Solution: Build for multiple platforms
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:latest --push .
```

### Slutpunkter för hälsa

och

```bash
# Verify buildx is available
docker buildx version

# Create a new builder instance
docker buildx create --name multiarch --driver docker-container --use

# Inspect and bootstrap the builder
docker buildx inspect --bootstrap

# List available platforms
docker buildx inspect | grep Platforms
```

### för orkestratorer

Flerarkitektur

```dockerfile
# Use official multi-arch base images
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base

# For platform-specific operations, use build arguments
ARG TARGETPLATFORM
ARG BUILDPLATFORM

RUN echo "Building on $BUILDPLATFORM for $TARGETPLATFORM"

# Install architecture-specific dependencies
RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
        apt-get update && apt-get install -y some-arm64-package; \
    elif [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
        apt-get update && apt-get install -y some-amd64-package; \
    fi
```

### : Körs på x86_64 och ARM64 (Apple Silicon, Raspberry Pi)

```bash
# Build and push for AMD64 and ARM64
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t myregistry/myapp:latest \
  -t myregistry/myapp:1.0.0 \
  --push \
  .

# Build without pushing (loads into local Docker)
# Note: Can only load one platform at a time
docker buildx build \
  --platform linux/amd64 \
  -t myapp:latest \
  --load \
  .

# Build and export to tar files
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t myapp:latest \
  -o type=tar,dest=./myapp.tar \
  .
```

### Se tabellen nedan.

Fullständigt projekt om GitHub

**för Dockerfile-exempel, bygg skript och API-dokumentation.**

```bash
# Build multi-arch images first
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:latest --push .

# Then use in compose
```

```yaml
services:
  web:
    image: myapp:latest  # Already built for multiple architectures
```

**Multi-Arkitektur bygger med Docker Buildx**

```bash
#!/bin/bash
# build-multiarch.sh

docker buildx build --platform linux/amd64,linux/arm64 \
  -t myregistry/web:latest \
  -f web/Dockerfile \
  --push \
  web/

docker buildx build --platform linux/amd64,linux/arm64 \
  -t myregistry/worker:latest \
  -f worker/Dockerfile \
  --push \
  worker/

docker-compose pull  # Pull the multi-arch images
docker-compose up -d
```

### Moderna program måste köras på flera arkitekturer: x86_64 (AMD64) för servrar, ARM64 för Raspberry Pi och Apple Silicon Macs, ibland även ARM32 för inbyggda enheter.

Varför mångarkitekturen är viktig

```yaml
name: Build and Push Multi-Arch Images

on:
  push:
    branches: [ main ]
    tags: [ 'v*' ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: myregistry/myapp
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=sha,prefix={{branch}}-

      - name: Build and push
        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=registry,ref=myregistry/myapp:buildcache
          cache-to: type=registry,ref=myregistry/myapp:buildcache,mode=max
```

Sätta upp buildx

- Docker Buildx ingår i Docker Desktop.
- För Linux:
- Multi-Arkitektur Dockerfile
- De flesta Dockerfiles fungerar utan ändringar, men här är några tips:
- Bygga för flera plattformar

## Multi-Arkitektur med Docker Compose

Tyvärr, Docker Compose stöder inte direkt buildx.

### Arbeten:

Alternativ 1: Pre-build-bilder

```bash
# Publish as a container image (no Dockerfile needed!)
dotnet publish --os linux --arch x64 -p:PublishProfile=DefaultContainer

# Specify image name and tag
dotnet publish \
  --os linux \
  --arch x64 \
  -p:PublishProfile=DefaultContainer \
  -p:ContainerImageName=myapp \
  -p:ContainerImageTag=1.0.0

# Multi-architecture
dotnet publish --os linux --arch arm64 -p:PublishProfile=DefaultContainer
```

### Alternativ 2: Bygg skript

Real-World Exempel: CI/CD Pipeline`.csproj`:

```xml
<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>

    <!-- Container Configuration -->
    <ContainerImageName>myapp</ContainerImageName>
    <ContainerImageTag>$(Version)</ContainerImageTag>
    <ContainerRegistry>myregistry.azurecr.io</ContainerRegistry>

    <!-- Base image (defaults to mcr.microsoft.com/dotnet/aspnet:9.0) -->
    <ContainerBaseImage>mcr.microsoft.com/dotnet/aspnet:9.0-alpine</ContainerBaseImage>

    <!-- Container runtime configuration -->
    <ContainerWorkingDirectory>/app</ContainerWorkingDirectory>
    <ContainerPort>8080</ContainerPort>
    <ContainerEnvironmentVariable Include="ASPNETCORE_ENVIRONMENT">Production</ContainerEnvironmentVariable>

    <!-- User (security best practice) -->
    <ContainerUser>app</ContainerUser>

    <!-- Labels -->
    <ContainerLabel Include="org.opencontainers.image.description">My awesome app</ContainerLabel>
    <ContainerLabel Include="org.opencontainers.image.source">https://github.com/me/myapp</ContainerLabel>
  </PropertyGroup>
</Project>
```

GitHub Actions arbetsflöde för multi-arkitektur bygger:

```bash
dotnet publish -p:PublishProfile=DefaultContainer
```

### Detta arbetsflöde:

1. **Utlösare på pushes till huvud- eller versionstaggar**Ställer in QEMU för plattformsoberoende emulering
2. **Bygger för AMD64 och ARM64**Skapar taggar automatiskt (grennamn, semantiska versioner, SHA)
3. **Använder register caching för snabbare byggen**.NET 9 Förbättringar av containrar
4. **.NET 9 introducerar betydande förbättringar av containerstöd, vilket gör det enklare än någonsin att containerize .NET-applikationer utan att ens skriva en Dockerfil.**Inbyggd publicering av containrar
5. **Med .NET 9 kan du publicera en containerized ansökan direkt:**Anpassa containeregenskaper

### Lägg till i din

```xml
<PropertyGroup>
  <!-- Enable trimming to remove unused code -->
  <PublishTrimmed>true</PublishTrimmed>
  <TrimMode>full</TrimMode>

  <!-- OR use Native AOT for even smaller, faster images -->
  <PublishAot>true</PublishAot>
</PropertyGroup>
```

Publicera sedan:

- **Fördelar med inbyggt stöd för containrar**Ingen Dockerfil behövs
- **: Minskar komplexiteten**Optimerade bilder
- **: Microsoft låtar bilderna för prestanda**Konsekvent

### : Standard bilder över alla .NET-appar

**Säkerhet**

```dockerfile
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
COPY ["MyApp.csproj", "."]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish

FROM mcr.microsoft.com/dotnet/aspnet:9.0
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "MyApp.dll"]
```

**: Automatiska basbilduppdateringar**

```bash
# Just this!
dotnet publish -p:PublishProfile=DefaultContainer
```

Mindre bilder

### : Trimming och AOT sammanställning stöd

**Trimning och AOT för mindre bilder**

- Resultat:
- Standardvärde
- : ~220MB
- Tillverkning utgående från material enligt vilket HS-nummer som helst, utom material enligt samma HS-nummer som produkten

**: ~110MB**

- Med AOT
- : ~12MB för enkla appar!
- Jämförelse: Dockerfile vs Inbyggd
- Traditionell Dockerfile-metod:

### Inbyggd inflygning av behållare:

Båda producerar liknande bilder, men den inbyggda metoden är enklare och mer underhållsbar.

```xml
<PropertyGroup>
  <ContainerBaseImage>mcr.microsoft.com/dotnet/aspnet:9.0-noble-chiseled</ContainerBaseImage>
</PropertyGroup>
```

När Dockerfile ska användas vs Inbyggd

- **Använd Dockerfil när:**Du behöver full kontroll över bilden
- **Installera systemberoenden**Komplexa flerstegsbyggen
- **Icke-standardiserade basbilder**Använd inbyggd när:

Standard .NET web/konsole apps

- Du vill ha enkelhet
- Genomsnittliga Microsoft-optimeringar

Snabb prototypering

## Chiseled Ubuntu bilder

.NET 9 stöder "chiseled" Ubuntu bilder - ultra-minimala basbilder:

### Fördelar:

Liten

1. **: ~50% mindre än vanliga bilder**Säker
2. **: Minimal attack yta (ingen pakethanterare, skal)**Snabbt
3. **: Snabbare drar och startar**Avsättningar:
4. **Inget skal (hårdare att felsöka)**Begränsade systemverktyg
5. **Perfekt för produktion där säkerhet och storlek betyder mest.**Introduktion till .NET Aspire

### .NET Aspire är en åsiktsrik, molnklar stack för att bygga distribuerade applikationer.

Tänk på det som Docker Komposiera på steroider, särskilt utformad för .NET microservices.

1. **Vad är Aspire?**Aspire ger:
2. **Orkestrering**: Kör och ansluta flera tjänster lokalt
3. **Tjänstupptäckt**: Tjänsterna hittar varandra automatiskt

### Tröskelvärde

**: Inbyggd loggning, mätvärden, spårning**

```bash
dotnet new aspire-starter -n MyDistributedApp
cd MyDistributedApp
```

**Komponenter**

```csharp
var builder = DistributedApplication.CreateBuilder(args);

// Add Redis cache
var cache = builder.AddRedis("cache");

// Add PostgreSQL database
var db = builder.AddPostgres("postgres")
               .AddDatabase("mydb");

// Add API service (references cache and db)
var api = builder.AddProject<Projects.MyApi>("api")
                 .WithReference(cache)
                 .WithReference(db);

// Add frontend (references API)
builder.AddProject<Projects.MyWeb>("web")
       .WithReference(api);

builder.Build().Run();
```

**: Förkonfigurerade integrationer (Redis, PostgreSQL, RabbitMQ, etc.)**

```csharp
// MyApi/Program.cs
var builder = WebApplication.CreateBuilder(args);

// Aspireing
3.  Multi-stage builds to reduce image size
4.  Use `.dockerignore` generously
5.  Alpine/chiseled images for smaller size
6.  Use volume mounts for development
7.  Configure appropriate resource limits
8.  Use health checks for orchestration

## Troubleshooting Common Issues

### Container Won't Start

```bash
# Check logs
docker logs container-name

# Common issues:
# 1. Port already in use
docker ps | grep 8080  # Find conflicting container
docker stop conflicting-container

# 2. Missing environment variables
docker inspect container-name | grep Env

# 3. Failed health check
docker inspect container-name | grep Health -A 20
```

### Utplacering

```bash
# Enable BuildKit for faster builds
export DOCKER_BUILDKIT=1

# Use build cache
docker build --cache-from myapp:latest -t myapp:latest .

# Check what's taking time
docker build --progress=plain -t myapp:latest .
```

### : Skapa Kubernetes/Docker Komposiera manifest

```bash
# Containers can't communicate
# Solution: Ensure they're on the same network
docker network ls
docker network inspect network-name

# DNS not working
# Container names are DNS names within Docker networks
docker exec web ping db  # Should work if both on same network
```

### Aspirera arkitektur

```bash
# Permission denied on volume
# Solution: Match user IDs
FROM ubuntu
RUN useradd -u 1000 appuser  # Match host user ID
USER appuser
```

## En aspirerande lösning har tre typer av projekt:

Appvärddator

- **: Orkesterar dina tjänster**Tjänsteprojekt
- **: Dina faktiska tjänster (WebAPI:er, arbetstagare, etc.)**Tjänstinställningar
- **: Delad konfiguration (loggning, hälsokontroller osv.)**Snabbt exempel
- **1. Vad är det som händer?**Skapa spira projekt:
- **Två.**Appvärddator (MyDistributedApp.AppHost/Program.cs):
- **3. Vad är det som händer?**Användning i din tjänst:

Långsamma byggen

### Nätverksfrågor

- [Frågor om volymbehörighet](https://docs.docker.com/)
- [Slutsatser](https://docs.docker.com/compose/compose-file/)
- [Docker har utvecklats från ett enkelt containeriseringsverktyg till en omfattande plattform för att bygga, frakta och driva moderna applikationer.](https://github.com/dotnet/dotnet-docker)
- [Om du är:](https://learn.microsoft.com/en-us/dotnet/aspire/)
- [Komma igång](https://github.com/NVIDIA/nvidia-container-toolkit)
- [: Master Dockerfile grunderna och innehållet i behållaren](https://github.com/docker/buildx)

Happy containerizing! 🐳
Bygga appar

```yaml
services:
  smtp4dev:
    image: rnwood/smtp4dev
    ports:
      - "3002:80"
      - "2525:25"
    volumes:
      - e:/smtp4dev-data:/smtp4dev
    restart: always

  postgres:
    image: postgres:16-alpine
    container_name: postgres
    ports:
      - "5432:5432"
    env_file:
      - .env
    volumes:
      - e:/data:/var/lib/postgresql/data
    restart: always
```

**: Leverage Docker Komposit för multi-service orkestrering**

- **Påskyndat ML**: Harness GPU-stöd för beräkningsintensiva arbetsbelastningar
- **Gå Multi-Plattform**: Använd buildx för ARM och AMD64 kompatibilitet
- **Förenklat .NET**: Embrace inbyggd container publicering

Bygga mikrotjänster[: Utforska .NET Sträva efter distribuerade applikationer](/dockercomposedevdeps)Containerekosystemet tillhandahåller verktyg för varje scenario.

### Starta enkelt, iterera, och gradvis anta avancerade funktioner när dina behov växer.

Ytterligare resurser

```yaml
services:
  # Core application
  mostlylucid:
    image: scottgal/mostlylucid:latest
    restart: always
    env_file: .env
    volumes:
      - ./markdown:/app/markdown
      - ./logs:/app/logs
    networks:
      - app_network
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: '1.0'
        reservations:
          memory: 256M

  # Database only
  db:
    image: postgres:16-alpine
    env_file: .env
    volumes:
      - db_data:/var/lib/postgresql/data
    networks:
      - app_network
    deploy:
      resources:
        limits:
          memory: 512M
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
      interval: 30s
      timeout: 5s
      retries: 3

  # Caddy for HTTPS
  caddy:
    image: caddy:latest
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
    networks:
      - app_network
    deploy:
      resources:
        limits:
          memory: 128M

volumes:
  db_data:
  caddy_data:

networks:
  app_network:
```

**Dockerdokumentation**

- **Docker komposera referens**.NET Container Bilder
- **.NET Aspire Dokumentation**Verktygslåda för NVIDIA-behållare`docker logs`Docker Buildx
- **ch kör bara vad du behöver:**Varför detta fungerar för utveckling:
- **SMTP4Dev**: Testa e-postfunktionalitet utan en riktig SMTP-server
- **PostgreSQL**: Matchar produktionsdatabas

### Totalt fotavtryck

: ~200MB RAM vs 2-4GB för full stack

**Se tabellen nedan.**

```bash
# Just app + database + reverse proxy
docker-compose up -d mostlylucid db caddy
```

**Riktlinjer för fullständigt utvecklingsberoende**

```bash
# Add lightweight monitoring
docker-compose up -d mostlylucid db caddy seq
# Use Seq free 10GB/month
```

**för installationsanvisningar.**

```bash
# Add everything
docker-compose up -d
```

### Resursbegränsad produktionsinställning

#### För en budget VPS (2-4GB RAM), prioritera viktiga tjänster:

```yaml
services:
  myapp:
    image: postgres:16-alpine     # 50% smaller than postgres:16
    # vs
    image: postgres:16            # Full Debian base
```

**Vad som är borttaget och alternativ:**Inga Prometheus/Grafana

#### : Använd extern övervakning (UptimeRobot, BetterStack fri nivå)

Ingen Seq

```yaml
db:
  image: postgres:16-alpine
  # One instance, multiple databases
  # Umami, Mostlylucid, etc. all share this PostgreSQL
```

**: Använd filbaserad loggning +**, eller Seq Cloud fri nivå

#### Inget Vakttornet

```yaml
easynmt:
  deploy:
    resources:
      limits:
        cpus: "2.0"      # Don't let translation consume all CPU
      reservations:
        cpus: "0.5"      # Guarantee minimum
```

: Manuella uppdateringar med GitHub Åtgärder anmälningar

#### Ingen översättningstjänst

: Kör på begäran i en separat behållare du startar/stoppar manuellt[Resursgränser](/imagesharpwithdocker): Förhindra en enda tjänst från att konsumera allt minne

```yaml
mostlylucid:
  volumes:
    - /mnt/imagecache:/app/wwwroot/cache  # ImageSharp cache persists across restarts
```

**Strategi för progressiv förbättring**Starta minimalt, lägg till tjänster vid behov:

#### Steg 1: Kärna (512MB-1GB VPS)

Steg 2: Lägg till observerbarhet (2GB VPS)
|---------|-----------------|---------------------|
Steg 3: Full Stack (4GB+ VPS)
Metoder för resursoptimering
1. Vad är det som händer?

**Använd alpina bilder**Besparingar

#### : Alpine bilder är 50-70% mindre

Två.

```bash
# Create a separate compose file
# translation-compose.yml
services:
  easynmt:
    image: easynmt/api:2.0.2-cpu
    ports:
      - "8888:8888"
    volumes:
      - /mnt/easynmt:/cache/

# Only run when needed
docker-compose -f translation-compose.yml up -d

# Translate your content
# ...

# Shut down when done
docker-compose -f translation-compose.yml down
```

**Delad databasinstans**Istället för en databas per tjänst, använd en PostgreSQL instans med flera databaser:

### Besparingar

: 400MB RAM per ytterligare databas du konsolidera

```yaml
# Minimal production compose
services:
  mostlylucid:
    image: scottgal/mostlylucid:latest
    restart: always
    env_file: .env
    volumes:
      - /mnt/markdown:/app/markdown
      - /mnt/logs:/app/logs
      - /mnt/imagecache:/app/wwwroot/cache
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    env_file: .env
    volumes:
      - /mnt/postgres:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready"]
      interval: 30s

  cloudflared:
    image: cloudflare/cloudflared:latest
    command: tunnel run --token ${CLOUDFLARED_TOKEN}
    restart: always

  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      WATCHTOWER_CLEANUP: "true"
      WATCHTOWER_LABEL_ENABLE: "true"
    command: --interval 3600  # Check once per hour, not every 5 minutes
```

**3. Vad är det som händer?**

- Begränsa CPU för bakgrundstjänster
- Detta förhindrar bakgrundsjobb från att svälta din webbapplikation.
- Fyra.

**Ihållande cachevolymer**

- Som omfattas av
- ImageSharp med Docker`docker logs`, montering cache kataloger förhindrar onödig upparbetning:
- Varför det är viktigt
- : Utan detta återskapar varje behållare alla miniatyrbilder/bearbetade bilder.
- För att uppnå detta mål har kommissionen beslutat att inleda ett förfarande enligt artikel 108.2 i fördraget om Europeiska unionens funktionssätt (nedan kallat EUF-fördraget).

### Använd externa tjänster (fria nivåer)

Tjänst  en självstämplat RAM-minne .external alternativ .

**till Seq  på ~500MB  på Seq Cloud (10GB/månad fri) .**

```bash
# Simple health check script
#!/bin/bash
while true; do
  curl -f http://localhost/healthz || echo "Health check failed!" | mail -s "Alert" you@example.com
  sleep 300
done
```

**på Prometheus + Grafana  på ~600MB  på Grafana moln (fri nivå)  på**

```bash
# Watch for errors
docker-compose logs -f --tail=100 | grep -i error

# Email on critical errors
docker-compose logs -f | grep -i "critical" | while read line; do
  echo "$line" | mail -s "Critical Error" you@example.com
done
```

**på Ummami  på ~200MB  på annat håll**

```bash
# Quick resource check
docker stats --no-stream

# Pretty output
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
```

## Strategi

: Offload observability till fria nivåer, hålla kärnan ansökan på din VPS.

### 6. Vad är det som händer?

Tjänster på fältet

```bash
# Add Aspire to your solution
dotnet new aspire-apphost -n Mostlylucid.AppHost
cd Mostlylucid.AppHost
```

**För sällan använda tjänster som översättning:**

```csharp
var builder = DistributedApplication.CreateBuilder(args);

// PostgreSQL with persistent data
var postgres = builder.AddPostgres("postgres")
    .WithDataVolume()  // Persistent storage
    .WithPgAdmin();     // Optional: PgAdmin for database management

var mostlylucidDb = postgres.AddDatabase("mostlylucid");
var umamiDb = postgres.AddDatabase("umami");

// Seq for centralized logging
var seq = builder.AddSeq("seq")
    .WithDataVolume();

// Redis for caching (if needed)
var redis = builder.AddRedis("cache")
    .WithDataVolume()
    .WithRedisCommander();  // Optional: Redis Commander UI

// Main blog application
var mostlylucid = builder.AddProject<Projects.Mostlylucid>("web")
    .WithReference(mostlylucidDb)
    .WithReference(seq)
    .WithReference(redis)
    .WithEnvironment("TranslateService__Enabled", "false")  // Disable for dev
    .WithHttpsEndpoint(port: 7240, name: "https");

// Umami analytics
var umami = builder.AddContainer("umami", "ghcr.io/umami-software/umami", "postgresql-latest")
    .WithReference(umamiDb)
    .WithEnvironment("DATABASE_TYPE", "postgresql")
    .WithEnvironment("TRACKER_SCRIPT_NAME", "getinfo")
    .WithEnvironment("API_COLLECT_ENDPOINT", "all")
    .WithHttpEndpoint(port: 3000, name: "http");

// Translation service (CPU version, with resource limits)
var translation = builder.AddContainer("easynmt", "easynmt/api", "2.0.2-cpu")
    .WithDataVolume("/cache")
    .WithHttpEndpoint(port: 8888, name: "http")
    .WithEnvironment("MODEL_FAMILY", "opus-mt");

// Scheduler service (Hangfire background jobs)
var scheduler = builder.AddProject<Projects.Mostlylucid_SchedulerService>("scheduler")
    .WithReference(mostlylucidDb)
    .WithReference(seq);

// Prometheus for metrics
var prometheus = builder.AddContainer("prometheus", "prom/prometheus", "latest")
    .WithDataVolume()
    .WithBindMount("./prometheus.yml", "/etc/prometheus/prometheus.yml")
    .WithHttpEndpoint(port: 9090);

// Grafana for visualization
var grafana = builder.AddContainer("grafana", "grafana/grafana", "latest")
    .WithDataVolume()
    .WithHttpEndpoint(port: 3001)
    .WithEnvironment("GF_SECURITY_ADMIN_PASSWORD", builder.Configuration["Grafana:AdminPassword"] ?? "admin");

builder.Build().Run();
```

### Besparingar

: 1-2 GB RAM när översättningstjänsten inte kör**Exemplet "Världens budget för värdskap"**Här är vad som körs på en $ 6 / månad Hetzner VPS (2 vCPU, 4 GB RAM):

```csharp
// Extensions.cs
public static class Extensions
{
    public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder)
    {
        // OpenTelemetry
        builder.Services.AddOpenTelemetry()
            .WithMetrics(metrics =>
            {
                metrics.AddAspNetCoreInstrumentation()
                    .AddHttpClientInstrumentation()
                    .AddRuntimeInstrumentation();
            })
            .WithTracing(tracing =>
            {
                if (builder.Environment.IsDevelopment())
                {
                    tracing.SetSampler(new AlwaysOnSampler());
                }

                tracing.AddAspNetCoreInstrumentation()
                    .AddHttpClientInstrumentation()
                    .AddEntityFrameworkCoreInstrumentation();
            });

        // Health checks
        builder.Services.AddHealthChecks()
            .AddCheck("self", () => HealthCheckResult.Healthy(), tags: new[] { "live" });

        return builder;
    }

    public static IApplicationBuilder MapDefaultEndpoints(this WebApplication app)
    {
        app.MapHealthChecks("/healthz");
        app.MapHealthChecks("/ready", new HealthCheckOptions
        {
            Predicate = check => check.Tags.Contains("ready")
        });

        return app;
    }
}
```

### Total resursanvändning:

```csharp
var builder = WebApplication.CreateBuilder(args);

// Add Aspire service defaults (telemetry, health checks)
builder.AddServiceDefaults();

// Add services
builder.AddNpgsqlDbContext<MostlylucidDbContext>("mostlylucid");
builder.AddRedisClient("cache");

// Existing service registrations...
// builder.Services.AddControllersWithViews();
// etc...

var app = builder.Build();

// Map Aspire default endpoints
app.MapDefaultEndpoints();

// Existing middleware...
app.Run();
```

### RAM: ~800MB (blad 3.2GB gratis)

**Disk: ~2GB**

1. **CPU: < 10 % tomgång, < 50 % vid belastning**: `dotnet run --project Mostlylucid.AppHost`Vad är annorlunda:
2. **Inga Prometheus/Grafana (använd UptimeRobot + Cloudflare Analytics)**Ingen Seq (använd
   - + enstaka grepp)
   - Ingen Umami (använd Cloudflare Web Analytics - gratis)
   - Vakttornet kontrollerar varje timme i stället för var femte minut
   - Ingen översättningstjänst (körs manuellt vid behov)
3. **Övervakning av en budget**Utan Prometheus/Grafana, använd dessa fria alternativ:
4. **Hälsoövervakning:**Loggövervakning:`.env`Användning av resurser:

**Aspire Version: .NET-sättet**

Nu ska vi tänka om hela stacken med hjälp av .NET Aspire.

```bash
# Generate Docker Compose
dotnet run --project Mostlylucid.AppHost -- \
  --publisher compose \
  --output-path ./deploy

# This creates a production-ready docker-compose.yml
cd deploy
docker-compose up -d
```

**Detta ger dig alla orkestrering fördelar med bättre .NET integration och en fantastisk utvecklarupplevelse.**Att sätta upp mål för de flesta

```yaml
services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres-data:/var/lib/postgresql/data

  mostlylucid-db:
    image: postgres:16
    # Database initialization

  seq:
    image: datalust/seq:latest
    environment:
      ACCEPT_EULA: Y
    volumes:
      - seq-data:/data

  web:
    image: scottgal/mostlylucid:latest
    environment:
      ConnectionStrings__mostlylucid: Host=postgres;Database=mostlylucid;Username=postgres;Password=${POSTGRES_PASSWORD}
      ConnectionStrings__cache: cache:6379
    depends_on:
      - postgres
      - cache
      - seq

  cache:
    image: redis:7-alpine
    volumes:
      - redis-data:/data

  # ... other services
```

### Först, skapa Aspire App Host:

Mestlylucid.AppHost/Program.cs:
|---------|---------------|-------------|
| **Sök efter standardvärden för tjänsten**Skapa
| **Mestlylucid.ServiceDefaults**Projekt:
| **Uppdatera Mestlylucid/Program.cs**Fördelarna med att sträva efter att närma sig
| **Utvecklingserfarenhet:** | `docker-compose up` | `dotnet run`Enkla kommandon
| **startar allt**Dashboard
| **: Vackert UI på http://localhost:15888 som visar:** | `docker logs`Alla tjänster med livestatus
| **Loggböcker från alla tjänster på ett och samma ställe**Distribuerade spår mellan olika tjänster
| **Metrisk och hälsokontroller**Tjänstupptäckt
| **: Tjänsterna hittar varandra automatiskt via namn**Inställning

### : Centraliserad i AppHost, inte mer

**jonglering**

- Produktionsutbyggnad:
- Generera utplaceringsmanifest från Aspire:
- Genererad docker-kompose.yml
- (förenklad):
- Aspirera mot traditionell Docker Komposit

**till funktionen  på Docker Komposiera  på .NET Aspire**

- Ställ in
- till Manuell YAML  och C# kod med IntelliSense
- Tjänstupptäckt
- till Manuell env vars  på automatisk  påse
- Observationsförmåga

**Ta med dig din egen inbyggda (OpenTeletry)**

- Utveckling
- + Dashboard
- Felsökning

### Bifoga till behållaren  på F5 i Visual Studio  och

Loggböcker

1. **[Centraliserad instrumentpanel](/dockercompose)**Spårning
2. **[Ställ in manuellt  på Automatiskt distribuerad spårning](/dockercomposedevdeps)**Tillverkning
3. **[Använd YAML direkt  och skapa manifest](/imagesharpwithdocker)**Att lära sig kurva
4. **["YAML syntax" C# som du redan känner](/dockercompose)**När du ska använda Aspire vs Docker Komposiera
5. **Använd Aspire när:**Bygga .NET mikrotjänster

**Du vill ha integrerad felsökning**

- Teamet är bekvämt med C#
- Du behöver distribuerad spårning utanför-boxen
- Du distribuerar till Azure Container Apps (inhemskt stöd)
- Använd Docker Compose när:
- Polyglotttjänster (Node.js, Python, Go, etc.)
- Team föredrar infrastruktur-som-kod YAML

## Laddar till en Docker-kompatibel värddator

### Du behöver maximal kontroll över configuration av behållare

1. Enkel användning av en enda tjänst
2. Använd båda:
3. Strävan efter lokal utveckling
4. Generera Docker Kompose för produktion distribution`latest`)
5. Bäst av båda världarna!
6. Utveckling av den här bloggens Docker Setup`.dockerignore`Denna bloggs Docker resa visar typisk progression:
7. 2024 juli - Enkel start
8. : Bara appen, Cloudflared och Vakttornet

### Augusti 2024 - Devberoenden

1. : Tjänster som endast avser utveckling
2. Augusti 2024 - ImageSharp Fixa
3. : lösta volymbehörigheter för cachelagring`.env`November 2024 - Full Stack
4. : Fullständig observerbarhet med Prometheus, Grafana, Seq
5. Idag`depends_on`: Strävan efter .NET-första utveckling
6. Viktiga lärdomar:
7. Starta enkelt, lägg till komplexitet endast när det behövs
8. Separata dev- och produktionskonfigurationer

### Resursbegränsningar hindrar en tjänst från att döda andra

1. Volymfästen för cacheminnen sparar betydande upparbetningstid
2. Vakttornet möjliggör autouppdateringar med noll nedtid
3. Observationsförmåga är värt resurskostnaden i produktionen
4. Sammanfattning av bästa praxis
5. Dockerfile bästa praxis
6. Använd flerstegsbyggen
7. Kör som användare utan root
8. Beställningsinstruktioner för optimal cachelagring

### Använd specifika basbildtaggar (inte

1. Inkludera hälsokontroller
2. Användning
3. för att utesluta onödiga filer
4. Minimera lager (kombinera RUN-kommandon)`.dockerignore`Använd byggargument för flexibilitet
5. Docker komponerar de bästa metoderna
6. Använd namngivna volymer för data
7. Genomföra hälsokontroller
8. Användning

## för hemligheter (aldrig begå)

### Definiera explicita nätverk

```bash
# Check logs
docker logs container-name

# Common issues:
# 1. Port already in use
docker ps | grep 8080  # Find conflicting container
docker stop conflicting-container

# 2. Missing environment variables
docker inspect container-name | grep Env

# 3. Failed health check
docker inspect container-name | grep Health -A 20
```

### Användning

```bash
# Enable BuildKit for faster builds
export DOCKER_BUILDKIT=1

# Use build cache
docker build --cache-from myapp:latest -t myapp:latest .

# Check what's taking time
docker build --progress=plain -t myapp:latest .
```

### med hälsovillkor

```bash
# Containers can't communicate
# Solution: Ensure they're on the same network
docker network ls
docker network inspect network-name

# DNS not working
# Container names are DNS names within Docker networks
docker exec web ping db  # Should work if both on same network
```

### Ställ in omstartsprinciper

```bash
# Permission denied on volume
# Solution: Match user IDs
FROM ubuntu
RUN useradd -u 1000 appuser  # Match host user ID
USER appuser
```

## Separata dev/prod-konfigurationer

Resursgränser i produktionen

### Säkerhet på bästa sätt

**Kör som användare utan root**

- Använd chiseled/minimal basbild[Skanna bilder för sårbarheter](/dockercompose)Håll basbilder uppdaterade
- Inte inkludera hemligheter i bilder[Använd skrivskyddade filsystem där det är möjligt](/dockercomposedevdeps)Begränsa behållarens kapacitet
- Använd Docker hemligheter eller externa hemliga chefer[Prestanda bästa praxis](/imagesharpwithdocker)Använd BuildKit för snabbare byggen

**Hävstångslagrets cachelagring**

- Flerstegsbyggen för att minska bildstorleken
- Användning
- generöst
- Alpine/chiseled bilder för mindre storlek
- Använd volymfästen för utveckling

**Anpassa lämpliga resursgränser**

- Använd hälsokontroller för orkestrering
- Felsökning av gemensamma frågor
- Container kommer inte att starta
- Långsamma byggen
- Nätverksfrågor
- Frågor om volymbehörighet

**Slutsatser**

- Docker har utvecklats från ett enkelt containeriseringsverktyg till en omfattande plattform för att bygga, frakta och driva moderna applikationer.
- Denna guide har tagit dig från grundläggande till produktionsklara driftsättningar, med verkliga exempel från att köra mestadelslucid.com.
- Nyckeluttagningar
- För nybörjare:
- Börja med att

**Grundläggande Docker Kompositinställning**

- - 3 tjänster
- Användning
- beroenden som endast är beroende av utveckling
- för lokalt arbete

### Lös vanliga frågor som

volymbehörigheter

tidigt
|-------|----------|-----------|------------|
| **För självhushållare på budget-VPS:**Startminimum: App + Databas + Omvänd Proxy (~800MB RAM)
| **Använd alpina bilder och resursgränser**Offload observability till fria nivåer (Seq Cloud, Grafana Cloud, UptimeRobot)
| **Kör dyra tjänster (översättning, ML) endast on-demand**En $6 / månad VPS kan köra en produktionsblogg med utrymme att spara
| **För produktionsanläggningar:**Hälsokontroller möjliggör nolltidsuppdateringar med Vakttornet
| **Separata nätverk ger säkerhet (frontend/backend isolering)**Bindfästen för data du behöver för säkerhetskopiering/access

**Namngivna volymer för Docker-hanterad lagring**CPU/minnesgränser förhindrar resurssvält

### Cloudflare Tunnel eliminerar behovet av offentliga IP-adresser

För .NET-utvecklare:

- **Inbyggd container publicering i .NET 9 eliminerar Dockerfiler för enkla appar**Chiseled Ubuntu bilder ger minimal attack yta[.NET Aspire erbjuder bäst i klassen lokal utveckling erfarenhet](/dockercompose)
- **Aspire kan generera Docker Compose för produktionsutveckling**OpenTelemetri integration kommer gratis med Aspire
- **För avancerade användningsfall:**GPU-containrar möjliggör ML/AI arbetsbelastning med 10-15x upphastighet
- **Multiarkitektur bygger stöd ARM64 och AMD64 från en källa**GitHub Actions automatiserar multiplattformsbyggen[Layer caching dramatiskt hastigheter upp upprepade byggnader](https://github.com/scottgal/mostlylucid-nmt)
- **Resan**Denna bloggs Docker evolution speglar typiska progression:

### Stage  och tjänster  på RAM-användning  på grund av komplexiteten

**Steg 1**

- [(Juli 2024) App + Tunnel  på ca 300MB](https://docs.docker.com/)
- [Steg 2](https://docs.docker.com/compose/compose-file/)
- [(Aug 2024)  till + Dev beroenden  till ~500MB  till Lärande](https://github.com/dotnet/dotnet-docker)
- [Steg 3](https://learn.microsoft.com/en-us/dotnet/aspire/)
- [(Aug 2024)  på + Volymfixar på ~500MB](https://github.com/NVIDIA/nvidia-container-toolkit)
- [Steg 4](https://github.com/docker/buildx)

**(Nov 2024)  och full observerbarhet .. ~3.5GB ..................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................**

1. [Steg 5](/dockercompose)(Idag)  på + spira alternativ  på Variabel  och Modern  på
2. [Mönstret](/dockercomposedevdeps): Börja enkelt, lösa problem när de uppstår, lägga till komplexitet endast när det behövs.
3. [Vad är nästa?](/imagesharpwithdocker)Beroende på din sökväg:
4. Att lära sig docka

**: Börja med**

- [Docker Komposiera grunderna](https://github.com/scottgal/mostlylucid-nmt)Självupptagande
- [: Prova den minimala VPS-inställningen från den här artikeln](https://github.com/scottgal/mostlylucidweb)Bygga mikrotjänster

: Utforska .NET Aspire

Happy containerizing! 🐳