This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
Docker Utveckling djupdykning: Från grunderna till avancerad .NET Containerization
Sunday, 09 November 2025
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.
- **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:
- Docker komposera- Komma igång med grundläggande multi-container setups (2024 juli)
- 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
- : Varje VM kör en full OS stack (Linux-kärna, systembibliotek, etc.) - tung och långsam att startaBehållare
- : Dela värdkärnan, paket endast programkod och beroenden - lätt och snabbtVarför containrar är viktiga för utvecklare
- **Containrar löser flera kritiska problem:**Miljökonsistens
- : Utveckling, testning och produktionsmiljöer är identiskaIsolering av beroendeförhållanden
- : 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
- : Flera bilder kan dela baslagerEffektivitet
- : Endast ändrade lager behöver laddas ner/laddas uppDockerfile bästa praxis
- **Här är en produktionsklar .NET Dockerfile med kommentarer:**Följande huvudprinciper illustrerades:
- Flerstegsbyggen: Separata bygg-/publicera steg minska den slutliga bildstorleken dramatiskt
- 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
- Hantera dessa individuellt medkommandon blir otympliga.
app_networkDocker Compose löser det här. - Komplett Real-World Exempel: Produktion Blogg PlattformHär är den.
/mnt/*Faktisk produktion - **som driver just denna webbplats (mestalylucid.com):**Nyckelproduktionsmönster:
- Ett enda nätverk: Alla tjänster på
- för enkelhetens skullBindfästen
- : Värdvägar () för ihållande data du behöver för att säkerhetskopiera / komma åt
- 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 basbilderscottgal/mostlylucid-nmt:cpuByggnader för flera arkitekturerscottgal/mostlylucid-nmt:gpu-min- Stöder AMD64 och ARM64scottgal/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:
- Utlösare på pushes till huvud- eller versionstaggarStäller in QEMU för plattformsoberoende emulering
- Bygger för AMD64 och ARM64Skapar taggar automatiskt (grennamn, semantiska versioner, SHA)
- Använder register caching för snabbare byggen.NET 9 Förbättringar av containrar
- **.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
- **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
- : ~50% mindre än vanliga bilderSäker
- **: Minimal attack yta (ingen pakethanterare, skal)**Snabbt
- : Snabbare drar och startarAvsättningar:
- **Inget skal (hårdare att felsöka)**Begränsade systemverktyg
- **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.
- **Vad är Aspire?**Aspire ger:
- Orkestrering: Kör och ansluta flera tjänster lokalt
- 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
- 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.
- Om du är:
- Komma igång
- : Master Dockerfile grunderna och innehållet i behållaren
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ållare
docker 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
- 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 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) .
# 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
- CPU: < 10 % tomgång, < 50 % vid belastning:
dotnet run --project Mostlylucid.AppHostVad är annorlunda: - **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)
-
- Övervakning av en budgetUtan Prometheus/Grafana, använd dessa fria alternativ:
- **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
- **Centraliserad instrumentpanel**Spårning
- **Ställ in manuellt på Automatiskt distribuerad spårning**Tillverkning
- **Använd YAML direkt och skapa manifest**Att lära sig kurva
- **"YAML syntax" C# som du redan känner**När du ska använda Aspire vs Docker Komposiera
- **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
- Enkel användning av en enda tjänst
- Använd båda:
- Strävan efter lokal utveckling
- Generera Docker Kompose för produktion distribution
latest) - Bäst av båda världarna!
- Utveckling av den här bloggens Docker Setup
.dockerignoreDenna bloggs Docker resa visar typisk progression: - 2024 juli - Enkel start
- : Bara appen, Cloudflared och Vakttornet
Augusti 2024 - Devberoenden
- : Tjänster som endast avser utveckling
- Augusti 2024 - ImageSharp Fixa
- : lösta volymbehörigheter för cachelagring
.envNovember 2024 - Full Stack - : Fullständig observerbarhet med Prometheus, Grafana, Seq
- Idag
depends_on: Strävan efter .NET-första utveckling - Viktiga lärdomar:
- Starta enkelt, lägg till komplexitet endast när det behövs
- Separata dev- och produktionskonfigurationer
Resursbegränsningar hindrar en tjänst från att döda andra
- Volymfästen för cacheminnen sparar betydande upparbetningstid
- Vakttornet möjliggör autouppdateringar med noll nedtid
- Observationsförmåga är värt resurskostnaden i produktionen
- Sammanfattning av bästa praxis
- Dockerfile bästa praxis
- Använd flerstegsbyggen
- Kör som användare utan root
- Beställningsinstruktioner för optimal cachelagring
Använd specifika basbildtaggar (inte
- Inkludera hälsokontroller
- Användning
- för att utesluta onödiga filer
- Minimera lager (kombinera RUN-kommandon)
.dockerignoreAnvänd byggargument för flexibilitet - Docker komponerar de bästa metoderna
- Använd namngivna volymer för data
- Genomföra hälsokontroller
- 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
- Använd chiseled/minimal basbildSkanna bilder för sårbarheterHåll basbilder uppdaterade
- Inte inkludera hemligheter i bilderAnvänd skrivskyddade filsystem där det är möjligtBegränsa behållarens kapacitet
- Använd Docker hemligheter eller externa hemliga cheferPrestanda bästa praxisAnvä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ä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
- (Juli 2024) App + Tunnel på ca 300MB
- Steg 2
- (Aug 2024) till + Dev beroenden till ~500MB till Lärande
- Steg 3
- (Aug 2024) på + Volymfixar på ~500MB
- Steg 4
(Nov 2024) och full observerbarhet .. ~3.5GB ..................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
- Steg 5(Idag) på + spira alternativ på Variabel och Modern på
- Mönstret: Börja enkelt, lösa problem när de uppstår, lägga till komplexitet endast när det behövs.
- Vad är nästa?Beroende på din sökväg:
- Att lära sig docka
: Börja med
- Docker Komposiera grundernaSjälvupptagande
- : Prova den minimala VPS-inställningen från den här artikelnBygga mikrotjänster
: Utforska .NET Aspire
Happy containerizing! 🐳