Docker Development Deep Dive: De la base à l’avant-garde .Containerisation NET
Introduction
Docker a fondamentalement transformé la façon dont nous construisons le navire, , et exploitons les applications. Ce qui commençait à être un simple outil de conteneurisation s’est transformé en un écosystème complet pour le développement et le déploiement d’applications modernes
C'est le quatrième et le plus complet article de ma série de Docker pour les développeurs .NETM SK1 Si vous êtes nouveau à Docker,, il se peut que vous désiriez commencer par :
- Docker Compose - Démarrer avec les installations de conteneurs multiples de base -Container 2 July
- Dépendances de développement avec Docker Compose - Établissement d'environnements dev locaux Août
- ImageSharp avec Docker - Règlement des questions relatives aux permis de volume Août
Dans cette plongée profonde, nous nous fonderons sur ces fondations pour étudier :
- Production-Docker Compose prêt: L’enchaînement réel qui exploite ce blog
- Self- hébergement sur des ressources limitées: Techniques pratiques d’optimisation pour les déploiements de VPS budgétaire
- Soutien GPU: Faire fonctionner les charges de travail ML dans des conteneurs
- Les architectures multi-: Soutien ARM64 et AMDM SK2
- Caractéristiques du conteneur .NET 9: Built-in container publishing without Dockerfiles
- .NET Aspire: L'approche moderne de l'organisation des conteneurs par le réseau .NET
NOTE: Il s'agit d'une partie de mes expériences avec l'AI / une façon d'épargner $1000 Claude Code Crédits WebM SK3 J'ai alimenté cet article par un BUNCH de documentsMST5 ma compréhensionMst6 des questions que j'ai eues pour générer cet articleM st7 C'est fun et remplit une lacune que je n'ai jamais vu remplie ailleursMSt9
Que vous déployez une simple application Web ou orchestriez une architecture de microservices complexe avec GPU, ce guide vous mène des bases du Docker à la production.
Docker Fundamentals: Comprendre les conteneurs
Qu'est-ce que Docker, Really?
À son cœur, Docker est une plate-forme de containerisation qui emballe votre application et toutes ses dépendances dans une unité standardisée appelée « container ».
Pensez-en ainsi:
- Machines virtuelles: Chacune des VMs exploite un stade d'exploitation complet.
- Contenants: Partagez le noyau de l'hôte, seuls les paquets code d'application et dépendances - léger et rapide
Pourquoi les contenants sont importants pour les développeurs
# The classic developer problem
"It works on my machine!"
# The container solution
"Ship your machine!"
Les contenants permettent de résoudre plusieurs problèmes critiques:
- Cohérence de l'environnement: DéveloppementM SK1 Essais, et environnements de production sont identiques
- Isolation par dépendance: Il n'y a plus de versions conflictantes de la bibliothèque
- Structures reproductibles: La même entrée = la même sortieM SK2 chaque fois
- Déploiement rapide: Démarrer les contenants en secondes , pas en minutes
- Efficacité des ressources: Faire fonctionner des dizaines de conteneurs sur un seul hôte
Concepts Docker essentiels
Images vs Containers
# 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
Images sont immuables, Systèmes de fichiers stratifiés. Chaque instruction dans un Dockerfile crée une nouvelle couche
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
Cette couche est puissante:
- Cachement: Les couches non modifiées sont réutilisées, accélérer les constructions
- Partage: Plusieurs images peuvent partager des couches de base
- Efficacité: Seules les couches modifiées doivent être téléchargées
Comprendre l’exécution du Dockerfile: Non votre machine!
Une source de confusion commune pour les débutants de Docker: Les commandes contenues dans un Dockerfile ne fonctionnent pas sur votre machine.
Voici ce qui se passe en réalité :
Your Machine (Windows/Mac/Linux)
↓ (reads Dockerfile)
Build Image (usually Linux)
↓ (executes RUN commands here)
Output Image (contains results)
Pourquoi cela importe:
# You're on Windows, writing this Dockerfile
FROM ubuntu:24.04
# This RUN command executes in Ubuntu, NOT on your Windows machine!
RUN apt-get update && apt-get install -y curl
# This copies FROM your Windows filesystem
COPY myapp.exe /app/
# This executes IN the Ubuntu container
RUN chmod +x /app/myapp.exe
Principaux points de vue:
- Système de fichier local: Votre
COPYetADDLes commandes sont lues de votre machine - Créer une image: Votre
RUNles commandes sont exécutées dans le contenant's OS (pas votre machine) - Image de sortie: L'image finale contient toutes les couches créées durant la construction
- Plateforme Cross-: Vous pouvez être sur Windows, bâtir une image Linux , en utilisant des commandes Linux
C'est pourquoi vous pouvez écrire apt-get commands dans un Dockerfile sur Windows - ils'ils ne fonctionnent pas sur Windows ! IlsMSC3ils fonctionnent à l’intérieur du conteneur de construction LinuxM SK4basé sur le contenant de construction
Exemple de situation de confusion:
FROM mcr.microsoft.com/dotnet/sdk:9.0 # This is Linux-based
# You might think: "But I'm on Windows, how can I use these Linux commands?"
RUN apt-get update # ← Executes in the Linux build container, not your Windows machine
RUN dotnet restore # ← Executes in the Linux build container
Le démon Docker traite la traduction entre votre système de fichier local et l'environnement de construction containerisé.
Les meilleures pratiques en matière de dockerfile
Voici une production de ', - et . .
# 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"]
Comprendre le flux de construction
Voici ce qui se passe au cours d’un docker à plusieurs étapes :
graph TB
subgraph "Your Machine"
A[Source Code<br/>*.cs, *.csproj]
B[Frontend Assets<br/>*.js, *.css]
C[Configuration<br/>appsettings.json]
D[Static Files<br/>wwwroot/]
end
subgraph "Stage 1: Build Container (SDK Image)"
E[dotnet/sdk:9.0<br/>~1.5GB]
F[Copy .csproj files]
G[dotnet restore<br/>Download NuGet packages]
H[Copy source code]
I[dotnet build<br/>Compile to DLLs]
J[Build artifacts<br/>/app/build/]
end
subgraph "Stage 2: Publish Container"
K[dotnet publish<br/>Optimize & trim]
L[Published output<br/>/app/publish/]
end
subgraph "Stage 3: Final Runtime Container (ASPNET Image)"
M[dotnet/aspnet:9.0<br/>~220MB]
N[Create app user<br/>Security]
O[Copy published files<br/>ONLY production artifacts]
P[Final image<br/>~250MB total]
end
subgraph "Frontend Build Pipeline (Parallel)"
Q[npm install<br/>node_modules/]
R[Webpack bundling<br/>*.js → dist/]
S[TailwindCSS + PostCSS<br/>*.css → dist/]
T[Optimized assets<br/>wwwroot/js/dist/<br/>wwwroot/css/dist/]
end
A --> F
A --> H
F --> G
G --> H
H --> I
I --> J
J --> K
K --> L
B --> Q
Q --> R
Q --> S
R --> T
S --> T
L --> O
T --> O
C --> O
D --> O
M --> N
N --> O
O --> P
Principales constatations tirées de ce processus:
- L'image du SDK est discardée: Le contenant SDK de 1.5GB est éjecté après avoir publié
- Cache de la couche: Copie
.csprojavant le code source signifie que la restauration de dépendance est cachée à moins que les dépendances ne changent - Assets de frontend: Construit séparément ( fréquemment par
npm run build) et copie dans l'image finale - Fichiers de configuration:
appsettings.jsonetwwwroot/contenu copié de votre machine, non construit - Image finale: Commence à partir de l'image minimale du temps d'exécution (~220MBM SK2 MSC3 votre app
- Seules les fichiers de production: Code de source , obj/, binM SK3 nodeMSC4modulesMST5 ne parvient jamais à l'image finale
Principes clés illustrés:
- Multi-stage builds: Établissement séparéM SK1 Étapes d'édition réduisent considérablement la taille finale de l'image
- Optimisation des couches: Copie des fichiers de dépendance avant le code source pour un meilleur caching
- Sécurité: Suivre en tant que non-utilisateur root
- Contrôles de santé: Les orchestrateurs de conteneurs peuvent surveiller la santé des applications
- Environnement explicite: Définir les défauts de production
Établissement et fonctionnement
# 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
Docker Compose: Multi-Container Orchestration
Docker Compose vous permet de définir et d'exécuter plusieurs applications de conteneurs-Containers1 Au lieu de gérer les contenants individuellement,, vous décritez l'ensemble de votre stack d'applications dans un fichier YAMLM SK3
Pourquoi Docker Compose?
Examiner une application Web typique .NET:
- ASP.NET Application Web de base
- Base de données PostgreSQL
- Redis cache
- Seq pour l'enregistrement
- Peut-être un service de travail de base
La gestion de ces questions individuellement avec docker run les commandes deviennent inefficaces. Docker Compose règle ce problème.
Complément Real-Exemple mondiale: Production Blog Platform
Voici ce qui suit : production réelle docker-compose.yml qui exploite ce même site (mostlylucid.netM SK2
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
Principaux modèles de production:
- Réseau unique: Tous les services sur
app_networkpour la simplicité - Établissement d'un réseau de télécommunications: Voies d'accueil (
/mnt/*) pour les données persistantes que vous devez sauvegarder - Volumes désignés: Docker-entreposage géré pour les données que vous n'avez pas
- Étiquettes de la tour d'observation: Seules les services de mise à jour marqués explicitement pour l'auto
- Limites de ressources: Les contraintes du CPU sur le service de traduction évitent la faim des ressources
- La cartographie externe des ports: PostgreSQL sur 5266 au lieu de 5432 pour éviter les conflits avec d'autres instances
- Les fichiers environnementaux: Secrets in
.envfichier (ne s'est jamais engagé à git)
Caractéristiques clés du Docker Compose
Dépendances en matière de services
services:
web:
depends_on:
db:
condition: service_healthy # Wait for health check
redis:
condition: service_started # Just wait for start
Docker Compose orchestre l’ordre de démarrage. Le condition: service_healthy Il faut que le contrôle de santé de la base de données passe avant de lancer l’application Web.
Variables environnementales et secrets
# .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
Pour les secrets de production, utilisez Docker Secrets ou des gestionnaires secrets externes (AWS Secrets Manager, Azure Key VaultM SK3 HashiCorp Vault≥).
Volumes désignés vs Montages soudées
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
Volumes désignés:
- géré par Docker
- Les données persistantes à travers le contenant reprend
- Possibilité de sauvegarde/restored avec les commandes Docker
- Cross-compatible avec la plateforme
Montants d'engrenage:
- Planification directe vers le système de fichiers d'hôte
- Utilisable pour le développement (rechargement de code vivantM SK1
- Fichiers de configuration, logs, téléchargements
Réseautage
networks:
frontend:
driver: bridge
backend:
driver: bridge
services:
web:
networks:
- frontend
- backend
db:
networks:
- backend # Not exposed to frontend
Réseaux assurent l’isolement. ici, la base de données n’est accessible que pour les services de backendM SK2 non directement exposéeMSC3
Examens de santé
services:
db:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
Les vérifications de santé permettent à Docker de:
- Déterminer si un contenant est effectivement prêt (non seulement commencé)
- Démarrer les contenants non sains
- Fournir le statut aux orchestrateurs (KubernetesM SK1 Docker Swarm)
Commandes de rédaction communes du Docker
# 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
Développement vs Production Composer les fichiers
Préoccupations séparées avec plusieurs fichiers de compose:
docker-composition.yml (baseM SK1
services:
web:
build: .
environment:
- ASPNETCORE_ENVIRONMENT=Development
docker-composition.overrideM SK2yml (développement
services:
web:
volumes:
- .:/app # Live code reloading
ports:
- "5000:8080"
docker-composition.prodM SK2yml (productionM SK1
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
Support GPU dans Docker: Accélérer les charges de travail ML
Apprentissage à la machine, calculs scientifiques , et applications de traitement vidéo nécessitent souvent une accélération des GPUM SK2 Docker appuie les GPU NVIDIA par l’entremise du jeu d’outils pour conteneurs NVIDIA.
Établissement de la trousse d'outils pour le conteneur NVIDIA
# 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
Dockerfile for GPU-Accelerated Python/PyTorch Application
# 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"]
Contenants GPU en cours
# 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
GPU dans Docker Compose
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
Real-Exemple mondiale: Service de traduction avec GPU et CPU Builds
Voici un exemple de production réelle de ' mostlylucid-nmt, un service de traduction des machines neuronales que j’ai construit qui permet à l’auto-translation sur ce blogM SK2
Le projet montre:
- Variations GPU et CPU - La même base de code, différentes images de base
- Les architectures multi- - Supporte AMD64 et ARMM SK2
- Images de Docker optimisées - Variations complètes et minimales
- Production-réaliste - Contrôles de santé, persistance du volumeM SK2 signalement approprié
GPU-Service de traduction accélérée
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:
CPU-Autres options seulement
Pour les environnements sans GPU, le même service fonctionne sur CPU:
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:
Variations d'image disponibles:
scottgal/mostlylucid-nmt:gpu- CUDA 12.6 avec support de GPU PyTorch (~5GB)scottgal/mostlylucid-nmt:cpu- CPUM SK1seulement, impression plus petite ~2.5GBMSC4scottgal/mostlylucid-nmt:gpu-min- Construction minimale d'un GPUM SK1 aucun modèle préchargé (~4GB)scottgal/mostlylucid-nmt:cpu-min- Construction minimale de la CPU (~1.5GB)
Principales caractéristiques:
- Accélération du GPU: 10-15x traduction plus rapide avec CUDA
- Modèle Auto-Trouver: Télécharge les modèles de traduction sur la demande
- Soutien en cas de rechute: Tries OpusM SK1MT → mBART50 → MMSC5MMST6 pour une couverture linguistique maximale
- Persistence du volume: Démarrage des modèles de cache à travers le réservoir
- Points finals de la santé:
/healthet/readypour les orchestrateurs - Multi-Architecture: Fonctionne sur xM SK1 et ARM64 (Apple SiliconMSC4 Raspberry PiMST5
Voir le projet complet sur GitHub pour les exemples de Dockerfile, scripts de construction, et documentation APIM SK2
Multi-Architecture Builds avec Docker Buildx
Les applications modernes doivent fonctionner sur plusieurs architectures.
Pourquoi la multi-Architecture est importante
# 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 .
Établissement de Buildx
Docker Buildx est inclus dans Docker Desktop. Pour Linux:
# 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
Multi-Architecture Dockerfile
La plupart des Dockerfiles fonctionnent sans changements, mais voici quelques conseils:
# 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
Établissement pour plusieurs plates-formes
# 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 \
.
Multi-Architecture avec Docker Compose
Malheureusement, Docker Compose ne supporte pas directement le buildxM SK2 Méthodes de travail:
Option 1: Pré-montrer les images
# 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
Option 2: Ébauche de script
#!/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
Exemple réelle-Exemplaire mondial:ICM SK2Pipeline CD
GitHub Actions workflow for multi-architecture builds:
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
Ce flux de travail:
- Triggers sur les pushes à l'onglet principal ou aux tags de version
- Établissement de QEMU pour l’émulation transversale de platforms
- Équipements pour AMD64 et ARM64
- Génie automatiquement les balises (nom de la brancheM SK1versions sémantiques,SHAMSC3
- Utilise le caching du registre pour les éditions plus rapides
Modèles de construction avancés du docker: Réel-Exemple mondiale
L'article 5 de la Loi sur l'immigration et le statut des réfugiés mostlyucid-nmt Ce projet montre comment construire et distribuer plusieurs variantes d'image à partir d'une base de code unique.
Établir une matrice de stratégie pour les variables
Le projet produit huit variantes d'image différentes pour les différents cas d'utilisation:
| Tag d'image | Architecture | Accélérateur | Préchargement du modèle | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
:cpu (:latest) |
AMDM SK2 ARM64 | CPU | 5 | Oui | Modèles | 6 | 7 | 8 | 9 | GB | 10 | Déploiements de CPU de production | 11 | ||
:cpu-min |
AMDM SK1 ARM64 | CPU | Non | ~1.5GB \ | Chargement de modèles dynamiques ≥ | ||||||||||
:gpu |
AMDM SK1 seulement | NVIDIA CUDA CSK3 Oui Models de (~100) SSK6 | ~5GB | SSK8 Déploiement des GPU de production | |||||||||||
:gpu-min |
AMD64 seulement | NVIDIA CUDA | Non M | ~4GB S | GPU avec modèles dynamiques R |
Pourquoi plusieurs variantes?
- Production (fullM SK1: Modèles préchargés = traduction instantanée
- Développement (minimalM SK1: Équipements rapides (~30s par rapport aux modèles montés
- GPU: 10-15x plus rapide pour les scénarios de hauts débitsM SK2
- CPU: Fonctionne partout, aucun matériel spécial
- ARM64: Raspberry PiM SK1 Apple Silicon, Serveurs ARM
Stratégie de stockage sous couche
Les Dockerfiles utilisent l’ordre des couches stratégiques pour maximiser la réutilisation du cache de construction:
Structure standard de Dockerfile du CPU:
FROM python:3.12-slim
# Layer 1: System dependencies (rarely changes)
RUN apt-get update && apt-get install -y --no-install-recommends \
git curl \
&& rm -rf /var/lib/apt/lists/*
# Layer 2: Python dependencies (changes when requirements.txt updates)
WORKDIR /app
COPY requirements-prod.txt .
RUN pip install --no-cache-dir -r requirements-prod.txt
# Layer 3: Model preloading (slowest layer, changes when model list changes)
ARG PRELOAD_LANGS="de,es,fr,it,nl,pl,pt,ru,zh,ja,ar,uk"
ARG PRELOAD_PAIRS=""
RUN python -c "from easynmt import EasyNMT; \
import os; \
langs = os.environ.get('PRELOAD_LANGS', '').split(','); \
pairs = os.environ.get('PRELOAD_PAIRS', '').split(',') if os.environ.get('PRELOAD_PAIRS') else []; \
model = EasyNMT('opus-mt'); \
[model.translate('warmup', source_lang='en', target_lang=lang) for lang in langs if lang]; \
[model.translate('warmup', source_lang=src, target_lang=tgt) for pair in pairs for src,tgt in [pair.split('->')] if pair]"
# Layer 4: Application code (changes frequently, rebuilds in seconds)
COPY app.py .
COPY src/ ./src/
# Runtime configuration
EXPOSE 8000
ENV PYTHONUNBUFFERED=1 \
MODEL_CACHE_DIR=/app/models \
WEB_CONCURRENCY=4
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8000", \
"--worker-class", "uvicorn.workers.UvicornWorker", \
"--timeout", "300", "--graceful-timeout", "5"]
Pourquoi cette ordonnance est-elle importante:
| Layer | Frequence de reconstitution MSC2 Temps de construction MSC3 Taux d'interruption du cache SMC4 | |||
|---|---|---|---|---|
| Image de base | Néanmoins Python2à moins que les versions ne changent | |||
| Défaillances du système | Rarement | |||
| Des défaillances de Python | Occasionnellement (Mises à jour des dépendances) M | ~60s | ||
| Précharge du modèle | Rarement changements de la liste des modèlesM SK3 M | 5-10min | ||
| Code d'application | Tous les engagements |
Résultat: La plupart des mises en place sont terminées dans ~3 secondes à l'aide de couches cachées
GPU vs CPU: Différences d'image de base
Dockerfile de CPU:
FROM python:3.12-slim
# CPU-optimized PyTorch (smaller, no CUDA)
RUN pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
# CPU performance tuning
ENV OMP_NUM_THREADS=4 \
MKL_NUM_THREADS=4 \
EASYNMT_BATCH_SIZE=16
Dockerfile GPU (Dockerfile .gpu):
FROM nvidia/cuda:12.6.2-cudnn-runtime-ubuntu24.04
# Install Python 3.12
RUN apt-get update && apt-get install -y \
python3.12 python3-pip \
&& rm -rf /var/lib/apt/lists/*
# CUDA-enabled PyTorch matching CUDA 12.6
RUN pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124
# GPU performance tuning
ENV CUDA_VISIBLE_DEVICES=0 \
EASYNMT_BATCH_SIZE=64 \
EASYNMT_MODEL_ARGS='{"torch_dtype":"fp16"}' \
MAX_INFLIGHT_TRANSLATIONS=1
# Runtime needs GPU access
# docker run --gpus all scottgal/mostlylucid-nmt:gpu
Principales différences:
- Image de base:
python:3.12-slim(300MBM SK1 vsnvidia/cuda:12.6.2-cudnn-runtime(1.8GBM SK1 - Voie PyTorch: CPU (~140MB) vs CUDA
- Taille des lots: CPUM SK1 vs GPU=64 (Les GPUs gèrent de façon efficace des lots plus importantsMSC4
- Précision: CPUM SK1FP32 par rapport à GPUMSC3FP~16 ( la moitié de la précision permet d'économiser la mémoire GPU
ARM64 Optimisations
Dockerfile. inclut ARM-ajustement spécifique:
FROM python:3.11-slim-bookworm # Debian Bookworm has better ARM support
# Minimal dependencies (ARM devices often storage-constrained)
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc g++ git curl \
&& rm -rf /var/lib/apt/lists/*
# ARM performance tuning (Raspberry Pi 4/5 with 4GB RAM)
ENV OMP_NUM_THREADS=3 \
MKL_NUM_THREADS=3 \
OPENBLAS_NUM_THREADS=3 \
EASYNMT_BATCH_SIZE=4 \
MAX_CACHED_MODELS=1 \
MEMORY_CRITICAL_THRESHOLD=70.0
# Single worker (memory constrained)
CMD ["gunicorn", "app:app", "-w", "1", \
"--bind", "0.0.0.0:8000", \
"--timeout", "300"]
ARM-optimisations spécifiques:
- Réduction du filage: 3 threads (vs S4 on xM SK4 for thermal throttling
- Échantillons plus petits: 4 vs 16 sur xM SK3 ≥(RAM limité)
- Employé unique: Prévient la SOOM sur les dispositifs 4GB
- Surveillance de la mémoire: Nettoyage agressif à l'utilisation de RAM 70%
- Démarrages conservateurs: Les périphériques ARM sont plus lentes , permettront davantage de temps
Variants minimaux: Chargement du modèle de temps d'exécution
Dockerfile.min approche:
FROM python:3.12-slim
# Dependencies only, NO model preloading
COPY requirements-prod.txt .
RUN pip install --no-cache-dir -r requirements-prod.txt
# Application code
COPY app.py .
COPY src/ ./src/
# Models loaded on-demand from volume
ENV MODEL_CACHE_DIR=/models
VOLUME ["/models"]
Utilisation avec mount de volume:
# Create persistent model cache
docker volume create translation-models
# First run: downloads models on-demand
docker run -d \
-v translation-models:/models \
-p 8888:8000 \
scottgal/mostlylucid-nmt:cpu-min
# Subsequent runs: reuse cached models
# Same volume mount, instant startup
Minimale vs Commerce complet-offs:
| Aspect | Image complète MSC2 Image minimale MSC3 | |
|---|---|---|
| Taille de l'image | 2.5GB | |
| Temps de construction | 5-10 minutes | |
| Premier début | Traduction immédiate | MSC2 téléchargement min de modèle SMC3 |
| Démarrages subséquents | instantaneus | instantanés MSC2 si le volume persisteMSc3 MSc4 |
| Utilisation du disque | 2.5GB par contenant | |
| Développement | itération lente | iteration rapide |
| Production | Aucune dépendance de réseau | Besoins d'une persistance du volume |
Scripts de construction multi-Variant automatisé
construction-total.sh construit toutes les variantes avec une version uniforme:
#!/bin/bash
# Generate version tags
VERSION=$(date +%Y%m%d.%H%M%S)
GIT_SHA=$(git rev-parse --short HEAD)
# Enable buildx for multi-platform
docker buildx create --use --name multiarch 2>/dev/null || true
echo "Building all variants for mostlylucid-nmt:${VERSION}"
# CPU Full (multi-platform)
docker buildx build \
--platform linux/amd64,linux/arm64 \
-f Dockerfile \
-t scottgal/mostlylucid-nmt:cpu \
-t scottgal/mostlylucid-nmt:latest \
-t scottgal/mostlylucid-nmt:${VERSION} \
--build-arg VERSION=${VERSION} \
--build-arg VCS_REF=${GIT_SHA} \
--push \
.
# CPU Minimal (multi-platform)
docker buildx build \
--platform linux/amd64,linux/arm64 \
-f Dockerfile.min \
-t scottgal/mostlylucid-nmt:cpu-min \
-t scottgal/mostlylucid-nmt:${VERSION}-min \
--build-arg VERSION=${VERSION} \
--push \
.
# GPU Full (AMD64 only)
docker build \
-f Dockerfile.gpu \
-t scottgal/mostlylucid-nmt:gpu \
-t scottgal/mostlylucid-nmt:${VERSION}-gpu \
--build-arg VERSION=${VERSION} \
--build-arg PRELOAD_LANGS="de,es,fr,it,nl,pl,pt,ru,zh,ja,ar,uk" \
--push \
.
# GPU Minimal (AMD64 only)
docker build \
-f Dockerfile.gpu.min \
-t scottgal/mostlylucid-nmt:gpu-min \
--push \
.
echo "All builds complete!"
echo "Images tagged with version: ${VERSION}"
Avantages de l’automatisation des bâtiments:
- Versionnement cohérent: Timbre + Git SHA pour la traçabilité
- Multi-platform: Ensembles de commande unique pour AMD64 et ARMM SK2
- Publication parallèle: Toutes les variantes sont poussées simultanément
- Préchargement souple: Contrôle des args pour construire les modèles à inclure
- CI/CD prêt: peut être déclenché par les actions de GitHub
Scénarios d'utilisation pratique
Scénario 1: Développement (Iteration rapideM SK2
# Use minimal image with volume mount
docker run -d \
-v ./models:/models \
-v ./src:/app/src \
-p 8888:8000 \
scottgal/mostlylucid-nmt:cpu-min
# Edit code locally, container picks up changes
# Models cached in volume, no re-download
Scénario 2:CPU de production (haute disponibilité)
# Use full image, no volume needed
docker run -d \
--restart always \
--memory=2g \
--cpus=2 \
-p 8888:8000 \
scottgal/mostlylucid-nmt:cpu
# Models preloaded, instant translation
# No external dependencies
Scénario 3: Production GPU (high throughputM SK2
# docker-compose.yml
services:
translation:
image: scottgal/mostlylucid-nmt:gpu
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
environment:
- CUDA_VISIBLE_DEVICES=0
- EASYNMT_BATCH_SIZE=64
Scénario 4: ARMM SK1 déploiement à bord (Raspberry Pi)
# Automatic platform selection
docker run -d \
--restart always \
--memory=3g \
-p 8888:8000 \
scottgal/mostlylucid-nmt:cpu
# Docker pulls ARM64 variant automatically
# Optimized for ARM performance
Principaux points à tirer des modèles de construction avancés
- Le caching de la couche est essentiel: Commander les instructions du Dockerfile par changement de fréquence
- Construire des variantes qui répondent à différents besoins: Production vs développement vs matériel restreint
- Multi-appui à la plateforme: Utiliser buildx pour AMD64 + ARMM SK3 à partir d'un seul Dockerfile
- Préchargement par rapport à la charge du temps d'exécution: Temps de construction du commerce pour le temps de démarrage
- Architecture-Optimisation spécifique: Fabrication de threads en tuneM SK1 Taille des lots, Limites de mémoire par plate-forme
- Questions d'automatisation: Les scripts assurent la cohérence entre les variantes
- Version tout: Timestamps + Git SHA pour la traçabilité
- Stratégie de volume: Volumes de cache persistants pour économiser le temps de régénération
Ces modèles provenant de la plupartucid-nmt démontrent la production-les pratiques de Docker prêtes applicables à toute application complexe avec plusieurs scénarios de déploiement .
.NET 9 Amélioration des conteneurs
.NET 9 introduit d'importantes améliorations au support des conteneurs, rendant plus facile que jamais de contenant les applications .NET sans même écrire un Dockerfile
Élaboré- dans Container Publishing
Avec .NET 9, vous pouvez publier directement une application contenant
# 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
Configuration des propriétés du conteneur
Ajouter à votre .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>
Puis publier:
dotnet publish -p:PublishProfile=DefaultContainer
Avantages de la prise en charge des conteneurs -
- Aucun Dockerfile n'est nécessaire: Réduit la complexité
- Images optimisées: Microsoft ajuste les images pour leur performance
- Cohérence: Images standard dans toutes les applications .NET
- Sécurité: Mise à jour automatique des images de base
- Images plus petites: Soutien à la compilation du trimming et de l'OT
Trimming et AOT pour des images plus petites
<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>
Résultats:
- Norme: ~220MB
- Avec le triage: ~110MB
- Avec AOT: ~12MB pour les applications simplesM SK2
Comparaison: Dockerfile vs Built-in
Approche traditionnelle de Dockerfile:
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
COPY ["MyApp.csproj", "."]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish
FROM mcr.microsoft.com/dotnet/aspnet:9.0
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "MyApp.dll"]
Équipement construit-approche en conteneur:
# Just this!
dotnet publish -p:PublishProfile=DefaultContainer
Les deux produits produisent des images similaires, mais l’approche structurée-in est plus simple et plus entretenable .
Quand utiliser Dockerfile vs Built-in
Utiliser Dockerfile lorsque:
- Vous avez besoin du contrôle complet de l'image
- Installation des dépendances du système
- Structures complexes multi-stage
- Non-images de base standard
Utiliser l’architecture édifiée-in lorsque:
- Applications standard .NET web/console
- Vous voulez la simplicité
- Utiliser les optimisations de Microsoft
- Fabrication rapide de prototypes
Chiseled Ubuntu Images
.NET 9 appuie "chiseled"images Ubuntu
<PropertyGroup>
<ContainerBaseImage>mcr.microsoft.com/dotnet/aspnet:9.0-noble-chiseled</ContainerBaseImage>
</PropertyGroup>
Avantages:
- Petite: ~50% plus petits que les images normales
- Sécurité: Surface d'attaque minimale (aucun gestionnaire de paquetsM SK2shell)
- Soutien rapide: Appuie et démarre plus rapidement
Commerce-offs
- Il n'y a pas de coque (qui est plus difficile à débuger)
- Utilités de réseau limitées
Perfect pour la production où la sécurité et la taille sont les plus importantes.
Introduction à .NET Aspire
.NET Aspire est un groupe d’experts opinionésM SK1 nuage - boucle prête à bâtir des applications distribuées. Pensez-le comme Docker Compose sur stéroïdesMSC4 spécialement conçu pour les microservices de
Qu'est-ce qu'Aspire?
Aspire fournit:
- Orchestrement: Faire fonctionner et relier plusieurs services localement
- Dévoilement des services: Les services se trouvent mutuellement automatiquement
- Télémétrie: Équipement construit- enregistrement interneM SK2 métriques , traçage
- Components: Pré-Intégrations configurées (RedisM SK3 PostgreSQLMST4 RabbitMQMSC5 etc MST6
- Déploiement: Générer des Kubernetes / Manifestes de compilation du Docker
Architecture d'Aspire
Une solution Aspire comporte trois types de projets:
- App Host: Orchestre vos services
- Projets de services: Vos services réels
- Défaults du service: Configuration partagée
Exemple rapide
1. Créer un projet Aspire:
dotnet new aspire-starter -n MyDistributedApp
cd MyDistributedApp
2. App Host MyDistributedApp.AppHostM SK3ProgramMSC4csMST5
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();
3. Utiliser dans votre service:
// MyApi/Program.cs
var builder = WebApplication.CreateBuilder(args);
// Aspire automatically configures these based on AppHost
builder.AddServiceDefaults();
builder.AddRedisClient("cache");
builder.AddNpgsqlDbContext<MyDbContext>("mydb");
var app = builder.Build();
app.MapDefaultEndpoints(); // Health, metrics, etc.
4. Faire tout
dotnet run --project MyDistributedApp.AppHost
Aspire lance des missiles
- Le tableau de bord à http://localhost:15888
- Tous les services avec une configuration appropriée
- Redis et PostgreSQL dans les conteneurs
- Traçage réparti entre les services
Aspire vs Docker Compose
Docker Compose:
- Langue-agnostique
- Infrastructure-focused
- Détection manuelle du service
- Trouvez votre propre observabilité
Aspire:
- .NET-specific
- Développement
- Détection automatique du service
- Méthode de télémétrie intégrée
- génère des manifestes de déploiement
Utiliser les deux: Aspiration pour le développement local , produit Docker Compose/Kubernetes pour la productionM SK3
Mettre en place des applications Aspire
Générer les manifestes de déploiement:
# Generate Docker Compose
dotnet run --project MyDistributedApp.AppHost -- \
--publisher compose \
--output-path ../deploy
# Generate Kubernetes manifests
dotnet run --project MyDistributedApp.AppHost -- \
--publisher manifest \
--output-path ../deploy/k8s
Puis déployer:
# Docker Compose
docker-compose -f deploy/docker-compose.yml up -d
# Kubernetes
kubectl apply -f deploy/k8s/
Components d'Aspire
Pré-les intégrations construites rendent l’ajout de services trivial
// Add various backing services
var redis = builder.AddRedis("cache");
var postgres = builder.AddPostgres("db").AddDatabase("mydb");
var rabbitmq = builder.AddRabbitMQ("messaging");
var mongodb = builder.AddMongoDB("mongo").AddDatabase("docs");
var sql = builder.AddSqlServer("sql").AddDatabase("business");
// Add Azure services
var storage = builder.AddAzureStorage("storage");
var cosmos = builder.AddAzureCosmosDB("cosmos");
var servicebus = builder.AddAzureServiceBus("messaging");
// Use in services
builder.AddProject<Projects.MyService>("service")
.WithReference(redis)
.WithReference(postgres)
.WithReference(rabbitmq);
Self-Hosting on Limited Resources: Optimisation pratique
L'exploitation d'un stade de pleine observabilité comme celui ci requiert des ressources importantes. Si vous 'êtes vous-mêmesM SK2vous êtes hébergé sur un VPS avec 4GB RAM ou un vieux ordinateur portableMスク4 voici des stratégies pratiques pour réduire la consommation de ressources tout en maintenant la fonctionnalitéMSC5
Dependences de développement seulement
Pour le développement local, vous n’avez pas besoin de la totalité du plate-forme de production devdeps-dockerM SK1compose.yml approche ne fonctionne que ce dont vous avez besoin:
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
Pourquoi cela fonctionne pour le développement:
- SMTP4Dev: Tester la fonctionnalité du courrier électronique sans un serveur SMTP réel
- PostgreSQL: Base de données sur la production correspondant
- Total des empreintes de pied: ~200MB RAM vs 2-4GB pour le stack complet
Voir le Guide des dépendances de développement complet pour les instructions de configuration.
Ressource-Établissement de production restreinte
Aux fins d’un budget VPS (2-4GB RAM ), Prioriter les services essentiels:
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:
Qu’est-ce qui a été supprimé et quelles sont les solutions de rechange?
- Aucun Prometheus/Grafana: Utiliser la surveillance externe (UptimeRobotM SK2 BetterStack free tier)
- Aucune séquence: Utiliser le fichier-logage basé sur les données +
docker logs, ou Seq Cloud, niveau gratuit - Aucune tour d'observation: Mise à jour manuelle avec les notifications des actions de GitHub
- Aucun service de traduction: Suivre sur-à la demande dans un contenant séparé que vous démarrezM SK2arrêter manuellement
- Limites de ressources: Protéger tout service unique de la consommation de toute mémoire
Stratégie d'amélioration progressive
Démarrer minimale, ajouter les services au besoin:
Étape 1: Core (512MBM SK2GB VPS)
# Just app + database + reverse proxy
docker-compose up -d mostlylucid db caddy
Étape 2: Ajouter l’observabilité (2GB VPSM SK2
# Add lightweight monitoring
docker-compose up -d mostlylucid db caddy seq
# Use Seq free 10GB/month
Étape 3: Équipe complète (4GBM SK2 VPS)
# Add everything
docker-compose up -d
Techniques d'optimisation des ressources
1. Utiliser des images alpines
services:
myapp:
image: postgres:16-alpine # 50% smaller than postgres:16
# vs
image: postgres:16 # Full Debian base
Épargnes: Les images alpines sont plus petites 50-70%
2. Instance de base de données partagée
Au lieu d’une base de données par service, utiliser une instance PostgreSQL avec plusieurs bases de données:
db:
image: postgres:16-alpine
# One instance, multiple databases
# Umami, Mostlylucid, etc. all share this PostgreSQL
Épargnes: 400MB RAM par base de données supplémentaire que vous consolidez
3. Limite CPU pour les services de base
easynmt:
deploy:
resources:
limits:
cpus: "2.0" # Don't let translation consume all CPU
reservations:
cpus: "0.5" # Guarantee minimum
Cela empêche les tâches de fond d'être faimées par votre application Web.
4. Volumes de cache persistants
Tel qu'il est indiqué dans ImageSharp avec Docker, le montage des répertoires de cache permet d'éviter un retraitement inutile
mostlylucid:
volumes:
- /mnt/imagecache:/app/wwwroot/cache # ImageSharp cache persists across restarts
Pourquoi cela est important: Sans cela, chaque nouveau démarrage du contenant régénére toutes les images miniaturesM SK2images traitées .
5. Utiliser des services externes ( Niveaux gratuits)
| Service | Automne |
|---|---|
| Seq | MSC2MB MSC3 Cloud Seq |
| Prometheus + Grafana MSC2 MSC3MB SMC4 Cloud de la Grafana | |
| Umami | ~200MB SMK3 Plausible (payé) ou lui-mêmeM SK6 hôte ailleurs SSK7 |
Stratégie: Offload observability to free tiers, keep core application on your VPS .
6. Sur-Services à la demande
Pour les services peu utilisés comme la traduction:
# 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
Épargnes: 1-2GB RAM lorsque le service de traduction n’est pas en cours
Real-Exemple d’hébergement budgétaire mondial
Voici ce qui fonctionne sur un $6/month Hetzner VPS.
# 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
Utilisation totale des ressources:
- RAM: M SK1MB (levées 3.2GB libres)
- Disque: ~2GB
- CPU: M SK1 en mode d'utilisation
Qu’est-ce qui diffère ?
- Aucun Prometheus/Grafana (utilisez UptimeRobot + Cloudflare AnalyticsM SK3
- Aucun Seq (utiliser
docker logs+ grep occasionnelM SK1 - Aucune Umami (utiliser Cloudflare Web Analytics - gratuitM SK2
- Contrôles horaires au lieu de tous les 5 minutes
- Aucun service de traduction (suivre manuellement lorsque nécessaire)
Surveillance du budget
Sans Prometheus/Grafana, utilisez ces solutions de rechange gratuitesM SK2
Surveillance de la santé:
# 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
Surveillance du log:
# 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
Utilisation des ressources:
# Quick resource check
docker stats --no-stream
# Pretty output
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
Version Aspire: La voie .NET
Maintenant, laissez 's réimaginer l’ensemble de la pile en utilisant .NET Aspire. Ce qui vous donne tous les avantages d’orchestrement avec une meilleure
Setting Up Aspire for Mostlylucid
Premièrement, créer l’Aspire App Host:
# Add Aspire to your solution
dotnet new aspire-apphost -n Mostlylucid.AppHost
cd Mostlylucid.AppHost
Mostlylucid.AppHost/Programme .csM SK3
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();
Défaults du service Aspire
Créer Utilisation des services par défaut Projet:
// 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;
}
}
Mise à jour Mostlylucid/Program.cs
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();
Avantages de l'approche Aspire
Expérience de développement:
- Commande unique:
dotnet run --project Mostlylucid.AppHostTout débute - Tableau de bord: Beautiful UI at httpM SK1localhost:15888 showingMSC3
- Tous les services dont le statut est vivant
- Logs de tous les services en un seul endroit
- Traces répartis entre les services
- Mesures et contrôles de santé
- Dévoilement des services: Les services se trouvent mutuellement automatiquement par le biais de noms
- Configuration: Centralisé dans AppHost, pas plus
.envJuggling
Déploiement de la production:
Générer des manifestes de déploiement à partir d’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
Docker généré-composition.yml (simplifiéM SK1
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
Aspire vs Traditional Docker Compose
| Caractéristiques | Composeur de docker MSC2 SMC3NET Aspire S | |
|---|---|---|
| Mise en place | Manuel YAML | Code C# avec IntelliSense |
| Dévoilement des services | Envelope manuelle vars | |
| Observabilité | Portez votre propre | Construit-dans MSC3OpenTelemetryMSC4 SMC5 |
| Développement | docker-compose up |
dotnet run Tableau de bord + |
| Débugging | Attacher au contenant | FM SK2 dans l'atelier visuel MSC3 |
| Logs | docker logs |
Tableau de bord centralisé |
| Traçage | Établissement manuelle | Traçage distribué automatique |
| Production | Utiliser YAML directement | Gérer des manifestes |
| Curve d'apprentissage | syntaxe YAML | CM SK2 vous connaissez déjà |
Quand utiliser Aspire vs Docker Compose
Utiliser Aspire lorsque:
- Établissement de microservices .NET
- Vous voulez un débugging intégré
- L’équipe est confortable avec C#
- Vous avez besoin d'un traçage distribué de la boîte
- Vous'vous déployez des applications de conteneurs Azure (appui natifM SK2
Utiliser Docker Compose lorsque:
- Services de polyglot (Node.js , PythonM SK3 GoMST4 etcMSC5
- L’équipe privilégie l’infrastructure-as-code YAML
- Déploiement sur un hôte compatible Docker-
- Vous avez besoin d'un contrôle maximal sur la configuration du contenant
- Simples déploiements de service unique-
Utiliser les deux :
- Aspirer au développement local
- Generate Docker Compose pour le déploiement de la production
- Le meilleur des deux mondes!
Évolution de ce blog's Docker Setup
Ce blog's Voyage du Docker montre une progression typique:
- Juillet 2024 - Début simple: Juste l’applicationM SK1 Cloudflared, et Watchtower
- Août 2024 - Dépendances en matière de développement: Développement additionnel -seulement services
- Août 2024 - Fixation de la compression d'image: Permis de volume résolus pour le caching
- Novembre 2024 - Stock complet: Observabilité complète avec Prometheus, GrafanaM SK2 Seq
- Aujourd'hui: Option Aspire pour le premier développement
Les leçons apprises:
- Démarrer simple, ajouter la complexité seulement lorsque nécessaire
- Séparer les configurations dev et de production
- Les limites des ressources empêchent un service de tuer d'autres
- Les montages de volume pour les caches permettent d'économiser un temps considérable de retraitement.
- La tour d'observation permet des mises à jour zéro-downtime auto-
- L’observabilité vaut le coût des ressources en production
Résumé des meilleures pratiques
Les meilleures pratiques en matière de dockerfile
- Utiliser des constructions multi-stage
- Run as non-root user
- Instructions d'ordre pour le caching optimal
- Utiliser des balises d'image de base spécifiques (non
latest) - Inclure les contrôles de santé
- Utilisation
.dockerignorepour exclure les fichiers inutiles - Réduire au minimum les couches (combiner les commandes RUN)
- Utiliser les arguments de construction pour la souplesse
Docker Compose Best Practices
- Utiliser des volumes désignés pour les données
- Mettre en œuvre des contrôles de santé
- Utilisation
.envpour les secrets (never commit) - Définir les réseaux explicites
- Utilisation
depends_onavec des conditions de santé - Établir les politiques de remarrage
- Séparer les configurations dev/prod
- Limites de ressources dans la production
Pratiques exemplaires en matière de sécurité
- Run as non-root user
- Utiliser les images de base minimales chiseled/
- Scanner les images pour des vulnérabilités
- Garder les images de base à jour
- Don' ne contiennent pas de secrets dans les images
- Utiliser read-seulement les systèmes de fichier lorsque possible
- Limiter les capacités des conteneurs
- Utiliser les secrets de Docker ou des gestionnaires externes
Pratiques exemplaires en matière de rendement
- Utiliser BuildKit pour des constructions plus rapides
- Cache de la couche d'élévation
- Multi-stage construit pour réduire la taille de l'image
- Utilisation
.dockerignoregénéreusement - Alpine/images chiselées pour plus petite taille
- Utiliser les montages de volume pour le développement
- Configurer les limites de ressources appropriées
- Utiliser des vérifications de santé pour l'orchestrement
Troubleshooting Common Issues
Contenant Won't Démarrage
# 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
Fabrications lentes
# 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 .
Questions relatives aux réseaux
# 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
Questions relatives aux permis de volume
# Permission denied on volume
# Solution: Match user IDs
FROM ubuntu
RUN useradd -u 1000 appuser # Match host user ID
USER appuser
Conclusion
Docker a évolué d’un outil de contenant simple à une plate-forme globale pour la construction, transports, et l’exploitation des applications modernes . Ce guide vous a conduit des fondations à la productionM SK3 déploiements déjà effectuésSSK4 avec des exemples réels-world depuis la mise en oeuvre principalementlucidMST6netSST7
Key Takeaways
Pour les débutants:
- Commencer par le Établissement de base du Docker Compose - seulement 3 services
- Utilisation développement-seulement dépendances pour le travail local
- Résoudre des problèmes communs comme permissions de volume précoce
Pour les Autochtones-Présidents sur le budget VPS:
- Démarrer minimale: App + Base de données + Proxy inverse (~800 RAMMBM SK4
- Utiliser des images alpines et les limites de ressources
- Offload observability to free tiers (Seq CloudM SK1 Grafana Cloud , UptimeRobot)
- Exécuter des services coûteux (traduction, MLM SK2 sur -demand seulement
- Un VPS mensuel $6/ peut gérer un blog de production avec des espaces à consacrer
Pour les déploiements de production:
- Les vérifications de santé permettent la mise à jour du temps d’arrêt zero- avec Watchtower
- Réseaux séparés assurent la sécurité (frontend/backend isolationM SK2
- Montants de joints pour les données que vous devez sauvegarder/access
- Volumes désignés pour le stockage géré par Docker-
- CPU/limites de mémoire empêchent la faim des ressources
- Cloudflare Tunnel élimine le besoin d'adresses IP publiques
Pour .Developpereurs NET:
- Élaboré - dans l’édition de conteneurs en .NET 9 élimine les Dockerfiles pour des applications simples
- Les images Chiseled Ubuntu fournissent une surface d'attaque minimale
- .NET Aspire offre les meilleures expériences de développement local de la classe
- Aspire peut générer Docker Compose pour le déploiement de la production
- L'intégration de OpenTelemetry est gratuite avec Aspire
Cases d'utilisation avancée:
- Les contenants GPU permettent la charge de travail ML/AI avec une vitesse accrue 10-15x
- Multi-architecture construit des supports ARM64 et AMDM SK2 à partir d'une source unique
- GitHub Actions automatise les constructions multi-platform
- Le caching des couches accélère considérablement les constructions répétées
Le voyage
Ce blog's L’évolution du Docker témoigne de la progression typique:
| Étape | Services MSC2 Usage du RAM MSC3 Complexité SMC4 | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| Étape 1 (juillet MSC1 MSC2 App SMC3 Tunnel ESC4 \MSC5MB \ESC6 Simple ESC7 | |||||||||
| Étape 2 (Août 2024) | 3 | Dépendances de développement | 4 | 5 | MB | 6 | Apprentissage | ||
| Étape 3 (Août 2024) SMK2 \ + Révisions de volume | ~500MB | Débugging | |||||||
| Étape 4 (Nouveau 2024) | |||||||||
| Étape 5 (À l'heure actuelle) | ≥+ Option d'aspiration | Variable | Moderne S |
Le modèle: Commencer par simpler, résoudre les problèmes à mesure qu’ils se posentM SK2 ajouter la complexité seulement lorsque nécessaireMSC3
Qu’est-ce que's Suivant?
Selon votre chemin:
- Docker d'apprentissage: Commencez par Docker Compose basics
- Self-Hosting: Essayez la configuration minimale de VPS à partir de cet article
- Établissement de microservices: Explore .NET Aspire
- Exécuter les charges de travail du ML: Consultez le mostlylucid-nmt service de traduction
- Multi-platform: Établir un buildx pour les builds ARM64 + AMDM SK3
Ressources
Documentation officielle:
- Documentation du docker
- Docker Compose Référence
- .NET Images de conteneurs
- .NET Aspire Documentation
- NVIDIA Container Toolkit
- Docker Buildx
Ce blog's Docker Series:
- Docker Compose - Début
- Dépendances en matière de développement - Établissement du dév local
- ImageSharp avec Docker - Permis de volume
- Cet article - plongée profonde dans la production
Projets connexes:
- mostlylucid-nmt - GPU/CPU service de traduction avec multiM SK2arch builds
- Source du blog la plus claire - Voir le code réel et composer les fichiers
Rappelez-vous: La meilleure architecture est celle qui répond à vos besoins sans trop de complexité.
Contenants heureux! 🐳