Docker Utveckling djupdykning: Från grunderna till avancerad .NET Containerization (Svenska (Swedish))

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

Sunday, 09 November 2025

//

38 minute read

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.**Om du är ny i Docker, kanske du vill börja med:
  2. Docker komposera- Komma igång med grundläggande multi-container setups (2024 juli)
  3. Utvecklingsberoenden med Docker Compose- 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

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å containrarVad ä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:

# 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 startaBehållare
  2. : Dela värdkärnan, paket endast programkod och beroenden - lätt och snabbtVarför containrar är viktiga för utvecklare
  3. **Containrar löser flera kritiska problem:**Miljökonsistens
  4. : Utveckling, testning och produktionsmiljöer är identiskaIsolering av beroendeförhållanden
  5. : Inga fler "DLL hell" eller motstridiga biblioteksversionerReproducerbara byggnader

: Samma indata = samma utdata, varje gång

Snabb utbyggnad

# 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 minuterResurseffektivitet

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 dockningskonceptBilder 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

# 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 baslagerEffektivitet
  2. : Endast ändrade lager behöver laddas ner/laddas uppDockerfile 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

# 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 runBetrakta en typisk .NET webbapplikation:

Webbappen ASP.NET Core

PostgreSQL- databas**Redis- cacheNamedocker-compose.yml**Seq för loggning

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 medkommandon blir otympliga.app_networkDocker Compose löser det här.
  2. Komplett Real-World Exempel: Produktion Blogg PlattformHä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 skullBindfä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.envVakttornets etiketter

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

Resursgränser

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ältcondition: service_healthyExtern hamnkartläggning

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

# .env file (never commit to git!)
DB_PASSWORD=super_secret_password
SMTP_PASSWORD=another_secret
services:
  web:
    environment:
      - DB_PASSWORD=${DB_PASSWORD}  # From .env file
      - STATIC_VALUE=production     # Hardcoded
    env_file:
      - .env                        # Load entire file

Miljöfiler

: Hemligheter i

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

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

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)

# 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.

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

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

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

services:
  web:
    image: registry.example.com/myapp:${VERSION}
    restart: always
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '2'
          memory: 2G
# 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

# 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:

# 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

# 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å):

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(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 ToolkitDockerfil för GPU-accelererad Python/PyTorch-applikation
  • Köra GPU-containrarGPU i Docker komposera
  • Real-World Exempel: Översättningstjänst med GPU och CPU ByggerHär är ett riktigt produktionsexempel från

Mest lucid-nmt

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:

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:cpuByggnader för flera arkitekturer
  • scottgal/mostlylucid-nmt:gpu-min- Stöder AMD64 och ARM64
  • scottgal/mostlylucid-nmt:cpu-minOptimerade Docker-bilder

- Både fullständiga och minimala varianter

  • Produktionsfärdig- Hälsokontroller, volympersistens, korrekt loggning
  • GPU-accelererad översättningstjänstEndast 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)/readyHuvuddrag:
  • GPU-acceleration: 10-15x snabbare översättning med CUDA

Modell Ladda ner automatiskt: Nedladdningar översättningsmodeller on-demandStö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

# 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

# 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

# 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)

# 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.

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

# Then use in compose
services:
  web:
    image: myapp:latest  # Already built for multiple architectures

Multi-Arkitektur bygger med Docker Buildx

#!/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

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

# 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:

<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:

dotnet publish -p:PublishProfile=DefaultContainer

Detta arbetsflöde:

  1. Utlösare på pushes till huvud- eller versionstaggarStäller in QEMU för plattformsoberoende emulering
  2. Bygger för AMD64 och ARM64Skapar 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

<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 containrarIngen Dockerfil behövs
  • : Minskar komplexitetenOptimerade bilder
  • : Microsoft låtar bilderna för prestandaKonsekvent

: Standard bilder över alla .NET-appar

Säkerhet

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

# 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.

<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 systemberoendenKomplexa flerstegsbyggen
  • Icke-standardiserade basbilderAnvä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 bilderSäker
  2. **: Minimal attack yta (ingen pakethanterare, skal)**Snabbt
  3. : Snabbare drar och startarAvsä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

dotnet new aspire-starter -n MyDistributedApp
cd MyDistributedApp

Komponenter

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.)

// 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

# 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

# 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

# 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änsterTjä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

Happy containerizing! 🐳 Bygga appar

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 applikationerContainerekosystemet tillhandahåller verktyg för varje scenario.

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

Ytterligare resurser

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 DokumentationVerktygslåda för NVIDIA-behållaredocker logsDocker 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.

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

Riktlinjer för fullständigt utvecklingsberoende

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

för installationsanvisningar.

# Add everything
docker-compose up -d

Resursbegränsad produktionsinställning

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

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

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

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 manuelltResursgränser: Förhindra en enda tjänst från att konsumera allt minne

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

Strategi för progressiv förbättringStarta 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 bilderBesparingar

: Alpine bilder är 50-70% mindre

Två.

# 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 databasinstansIstället för en databas per tjänst, använd en PostgreSQL instans med flera databaser:

Besparingar

: 400MB RAM per ytterligare databas du konsolidera

# 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 Dockerdocker 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) .

# Simple health check script
#!/bin/bash
while true; do
  curl -f http://localhost/healthz || echo "Health check failed!" | mail -s "Alert" [email protected]
  sleep 300
done

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

# 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" [email protected]
done

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

# 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

# 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:

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):

// 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:

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.AppHostVad ä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 budgetUtan Prometheus/Grafana, använd dessa fria alternativ:
  4. **Hälsoövervakning:**Loggövervakning:.envAnvändning av resurser:

Aspire Version: .NET-sättet

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

# 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

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änstenSkapa | Mestlylucid.ServiceDefaultsProjekt: | Uppdatera Mestlylucid/Program.csFördelarna med att sträva efter att närma sig | Utvecklingserfarenhet: | docker-compose up | dotnet runEnkla kommandon | startar alltDashboard | : Vackert UI på http://localhost:15888 som visar: | docker logsAlla tjänster med livestatus | Loggböcker från alla tjänster på ett och samma ställeDistribuerade spår mellan olika tjänster | Metrisk och hälsokontrollerTjänstupptäckt | : Tjänsterna hittar varandra automatiskt via namnInstä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**Spårning
  2. **Ställ in manuellt på Automatiskt distribuerad spårning**Tillverkning
  3. **Använd YAML direkt och skapa manifest**Att lära sig kurva
  4. **"YAML syntax" C# som du redan känner**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 distributionlatest)
  5. Bäst av båda världarna!
  6. Utveckling av den här bloggens Docker Setup.dockerignoreDenna 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.envNovember 2024 - Full Stack
  4. : Fullständig observerbarhet med Prometheus, Grafana, Seq
  5. Idagdepends_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).dockerignoreAnvä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

# 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

# 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

# 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

# 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

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änserOffload observability till fria nivåer (Seq Cloud, Grafana Cloud, UptimeRobot) | Kör dyra tjänster (översättning, ML) endast on-demandEn $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 lagringCPU/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 apparChiseled Ubuntu bilder ger minimal attack yta.NET Aspire erbjuder bäst i klassen lokal utveckling erfarenhet
  • Aspire kan generera Docker Compose för produktionsutvecklingOpenTelemetri 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ällaGitHub Actions automatiserar multiplattformsbyggenLayer caching dramatiskt hastigheter upp upprepade byggnader
  • ResanDenna bloggs Docker evolution speglar typiska progression:

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

Steg 1

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

  1. Steg 5(Idag) på + spira alternativ på Variabel och Modern på
  2. Mönstret: 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?Beroende på din sökväg:
  4. Att lära sig docka

: Börja med

: Utforska .NET Aspire

Happy containerizing! 🐳

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.