754 lines
17 KiB
Markdown
754 lines
17 KiB
Markdown
---
|
|
name: docker-platform-guide
|
|
description: Platform-specific Docker considerations for Windows, Linux, and macOS
|
|
---
|
|
|
|
## 🚨 CRITICAL GUIDELINES
|
|
|
|
### Windows File Path Requirements
|
|
|
|
**MANDATORY: Always Use Backslashes on Windows for File Paths**
|
|
|
|
When using Edit or Write tools on Windows, you MUST use backslashes (`\`) in file paths, NOT forward slashes (`/`).
|
|
|
|
**Examples:**
|
|
- ❌ WRONG: `D:/repos/project/file.tsx`
|
|
- ✅ CORRECT: `D:\repos\project\file.tsx`
|
|
|
|
This applies to:
|
|
- Edit tool file_path parameter
|
|
- Write tool file_path parameter
|
|
- All file operations on Windows systems
|
|
|
|
|
|
### Documentation Guidelines
|
|
|
|
**NEVER create new documentation files unless explicitly requested by the user.**
|
|
|
|
- **Priority**: Update existing README.md files rather than creating new documentation
|
|
- **Repository cleanliness**: Keep repository root clean - only README.md unless user requests otherwise
|
|
- **Style**: Documentation should be concise, direct, and professional - avoid AI-generated tone
|
|
- **User preference**: Only create additional .md files when user specifically asks for documentation
|
|
|
|
|
|
---
|
|
|
|
# Docker Platform-Specific Guide
|
|
|
|
This skill provides detailed guidance on Docker differences, considerations, and optimizations for Windows, Linux, and macOS platforms.
|
|
|
|
## Linux
|
|
|
|
### Advantages
|
|
|
|
- **Native containers:** No virtualization layer overhead
|
|
- **Best performance:** Direct kernel features (cgroups, namespaces)
|
|
- **Full feature set:** All Docker features available
|
|
- **Production standard:** Most production deployments run on Linux
|
|
- **Flexibility:** Multiple distributions supported
|
|
|
|
### Platform Features
|
|
|
|
**Container Technologies:**
|
|
- Namespaces: PID, network, IPC, mount, UTS, user
|
|
- cgroups v1 and v2 for resource control
|
|
- Overlay2 storage driver (recommended)
|
|
- SELinux and AppArmor for mandatory access control
|
|
|
|
**Storage Drivers:**
|
|
```bash
|
|
# Check current driver
|
|
docker info | grep "Storage Driver"
|
|
|
|
# Recommended: overlay2
|
|
# /etc/docker/daemon.json
|
|
{
|
|
"storage-driver": "overlay2"
|
|
}
|
|
```
|
|
|
|
### Linux-Specific Configuration
|
|
|
|
**Daemon Configuration** (`/etc/docker/daemon.json`):
|
|
```json
|
|
{
|
|
"storage-driver": "overlay2",
|
|
"log-driver": "json-file",
|
|
"log-opts": {
|
|
"max-size": "10m",
|
|
"max-file": "3"
|
|
},
|
|
"live-restore": true,
|
|
"userland-proxy": false,
|
|
"userns-remap": "default",
|
|
"icc": false,
|
|
"default-ulimits": {
|
|
"nofile": {
|
|
"Name": "nofile",
|
|
"Hard": 64000,
|
|
"Soft": 64000
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**User Namespace Remapping:**
|
|
```bash
|
|
# Enable in daemon.json
|
|
{
|
|
"userns-remap": "default"
|
|
}
|
|
|
|
# Restart Docker
|
|
sudo systemctl restart docker
|
|
|
|
# Result: root in container = unprivileged user on host
|
|
```
|
|
|
|
### SELinux Integration
|
|
|
|
```bash
|
|
# Check SELinux status
|
|
sestatus
|
|
|
|
# Run container with SELinux enabled
|
|
docker run --security-opt label=type:svirt_sandbox_file_t myimage
|
|
|
|
# Volume labels
|
|
docker run -v /host/path:/container/path:z myimage # Private label
|
|
docker run -v /host/path:/container/path:Z myimage # Shared label
|
|
```
|
|
|
|
### AppArmor Integration
|
|
|
|
```bash
|
|
# Check AppArmor status
|
|
sudo aa-status
|
|
|
|
# Run with default Docker profile
|
|
docker run --security-opt apparmor=docker-default myimage
|
|
|
|
# Create custom profile
|
|
sudo aa-genprof docker run myimage
|
|
```
|
|
|
|
### Systemd Integration
|
|
|
|
```bash
|
|
# Check Docker service status
|
|
sudo systemctl status docker
|
|
|
|
# Enable on boot
|
|
sudo systemctl enable docker
|
|
|
|
# Restart Docker
|
|
sudo systemctl restart docker
|
|
|
|
# View logs
|
|
sudo journalctl -u docker -f
|
|
|
|
# Configure service
|
|
sudo systemctl edit docker
|
|
```
|
|
|
|
### cgroup v1 vs v2
|
|
|
|
```bash
|
|
# Check cgroup version
|
|
stat -fc %T /sys/fs/cgroup/
|
|
|
|
# If using cgroup v2, ensure Docker version >= 20.10
|
|
|
|
# /etc/docker/daemon.json
|
|
{
|
|
"exec-opts": ["native.cgroupdriver=systemd"]
|
|
}
|
|
```
|
|
|
|
### Linux Distribution Specifics
|
|
|
|
**Ubuntu/Debian:**
|
|
```bash
|
|
# Install Docker
|
|
sudo apt-get update
|
|
sudo apt-get install ca-certificates curl
|
|
sudo install -m 0755 -d /etc/apt/keyrings
|
|
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
|
|
sudo chmod a+r /etc/apt/keyrings/docker.asc
|
|
|
|
echo \
|
|
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
|
|
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
|
|
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|
|
|
sudo apt-get update
|
|
sudo apt-get install docker-ce docker-ce-cli containerd.io
|
|
|
|
# Non-root user
|
|
sudo usermod -aG docker $USER
|
|
```
|
|
|
|
**RHEL/CentOS/Fedora:**
|
|
```bash
|
|
# Install Docker
|
|
sudo dnf -y install dnf-plugins-core
|
|
sudo dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
|
|
sudo dnf install docker-ce docker-ce-cli containerd.io
|
|
|
|
# Start Docker
|
|
sudo systemctl start docker
|
|
sudo systemctl enable docker
|
|
|
|
# Non-root user
|
|
sudo usermod -aG docker $USER
|
|
```
|
|
|
|
**Alpine:**
|
|
```bash
|
|
# Install Docker
|
|
apk add docker docker-compose
|
|
|
|
# Start Docker
|
|
rc-update add docker boot
|
|
service docker start
|
|
```
|
|
|
|
## macOS
|
|
|
|
### Architecture
|
|
|
|
- **Docker Desktop:** Required (no native Docker on macOS)
|
|
- **Virtualization:** Uses HyperKit (Intel) or Virtualization.framework (Apple Silicon)
|
|
- **Linux VM:** Containers run in lightweight Linux VM
|
|
- **File sharing:** osxfs or VirtioFS for bind mounts
|
|
|
|
### macOS-Specific Considerations
|
|
|
|
**Resource Allocation:**
|
|
```
|
|
Docker Desktop → Preferences → Resources → Advanced
|
|
- CPUs: Allocate based on workload (default: half available)
|
|
- Memory: Allocate generously (default: 2GB, recommend 4-8GB)
|
|
- Swap: 1GB minimum
|
|
- Disk image size: 60GB+ for development
|
|
```
|
|
|
|
**File Sharing Performance:**
|
|
|
|
Traditional osxfs is slow. Improvements:
|
|
1. **VirtioFS:** Enable in Docker Desktop settings (faster)
|
|
2. **Delegated/Cached mounts:**
|
|
|
|
```yaml
|
|
volumes:
|
|
# Host writes delayed (best for source code)
|
|
- ./src:/app/src:delegated
|
|
|
|
# Container writes cached (best for build outputs)
|
|
- ./build:/app/build:cached
|
|
|
|
# Default consistency (slowest but safest)
|
|
- ./data:/app/data:consistent
|
|
```
|
|
|
|
**Network Access:**
|
|
|
|
```bash
|
|
# Access host from container
|
|
host.docker.internal
|
|
|
|
# Example: Connect to host PostgreSQL
|
|
docker run -e DATABASE_URL=postgresql://host.docker.internal:5432/db myapp
|
|
```
|
|
|
|
### Apple Silicon (M1/M2/M3) Specifics
|
|
|
|
**Architecture Considerations:**
|
|
```bash
|
|
# Check image architecture
|
|
docker image inspect node:20-alpine | grep Architecture
|
|
|
|
# M-series Macs are ARM64
|
|
# Some images only available for AMD64
|
|
|
|
# Build multi-platform
|
|
docker buildx build --platform linux/amd64,linux/arm64 -t myapp .
|
|
|
|
# Run AMD64 image on ARM (via emulation)
|
|
docker run --platform linux/amd64 myimage # Slower
|
|
```
|
|
|
|
**Rosetta 2 Integration:**
|
|
```
|
|
Docker Desktop → Features in development → Use Rosetta for x86/amd64 emulation
|
|
```
|
|
Faster AMD64 emulation on Apple Silicon.
|
|
|
|
### macOS Docker Desktop Settings
|
|
|
|
**General:**
|
|
- ✅ Start Docker Desktop when you log in
|
|
- ✅ Use VirtioFS (better performance)
|
|
- ✅ Use Virtualization framework (Apple Silicon)
|
|
|
|
**Resources:**
|
|
```
|
|
CPUs: 4-6 (for development)
|
|
Memory: 6-8 GB (for development)
|
|
Swap: 1-2 GB
|
|
Disk image size: 100+ GB (grows dynamically)
|
|
```
|
|
|
|
**Docker Engine:**
|
|
```json
|
|
{
|
|
"builder": {
|
|
"gc": {
|
|
"enabled": true,
|
|
"defaultKeepStorage": "20GB"
|
|
}
|
|
},
|
|
"experimental": false,
|
|
"features": {
|
|
"buildkit": true
|
|
}
|
|
}
|
|
```
|
|
|
|
### macOS File Permissions
|
|
|
|
```bash
|
|
# macOS user ID and group ID
|
|
id -u # Usually 501
|
|
id -g # Usually 20
|
|
|
|
# Match in container
|
|
docker run --user 501:20 myimage
|
|
|
|
# Or in Dockerfile
|
|
RUN adduser -u 501 -g 20 appuser
|
|
USER appuser
|
|
```
|
|
|
|
### macOS Development Workflow
|
|
|
|
```yaml
|
|
# docker-compose.yml for development
|
|
version: '3.8'
|
|
|
|
services:
|
|
app:
|
|
build: .
|
|
volumes:
|
|
# Source code with delegated (better performance)
|
|
- ./src:/app/src:delegated
|
|
# node_modules in volume (much faster than bind mount)
|
|
- node_modules:/app/node_modules
|
|
ports:
|
|
- "3000:3000"
|
|
environment:
|
|
- NODE_ENV=development
|
|
|
|
volumes:
|
|
node_modules:
|
|
```
|
|
|
|
### Common macOS Issues
|
|
|
|
**Problem:** Slow file sync
|
|
**Solution:**
|
|
- Use VirtioFS
|
|
- Use delegated/cached mounts
|
|
- Store dependencies in volumes (not bind mounts)
|
|
|
|
**Problem:** High CPU usage
|
|
**Solution:**
|
|
- Reduce file watching
|
|
- Exclude large directories from file sharing
|
|
- Allocate more resources
|
|
|
|
**Problem:** Port already in use
|
|
**Solution:**
|
|
```bash
|
|
# Find process using port
|
|
lsof -i :PORT
|
|
kill -9 PID
|
|
```
|
|
|
|
## Windows
|
|
|
|
### Windows Container Types
|
|
|
|
**1. Linux Containers on Windows (LCOW):**
|
|
- Most common for development
|
|
- Uses WSL2 or Hyper-V backend
|
|
- Runs Linux containers
|
|
- Good compatibility
|
|
|
|
**2. Windows Containers:**
|
|
- Native Windows containers
|
|
- For Windows-specific workloads
|
|
- Requires Windows Server base images
|
|
- Less common in development
|
|
|
|
### Windows Backend Options
|
|
|
|
**WSL2 Backend (Recommended):**
|
|
- Faster
|
|
- Better resource usage
|
|
- Native Linux kernel
|
|
- Requires Windows 10/11 (recent versions)
|
|
|
|
**Hyper-V Backend:**
|
|
- Older option
|
|
- More resource intensive
|
|
- Works on older Windows versions
|
|
|
|
### WSL2 Configuration
|
|
|
|
**Enable WSL2:**
|
|
```powershell
|
|
# Run as Administrator
|
|
wsl --install
|
|
|
|
# Or manually
|
|
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
|
|
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
|
|
|
|
# Set WSL2 as default
|
|
wsl --set-default-version 2
|
|
|
|
# Install Ubuntu (or other distro)
|
|
wsl --install -d Ubuntu
|
|
```
|
|
|
|
**Docker Desktop Integration:**
|
|
```
|
|
Settings → Resources → WSL Integration
|
|
- Enable integration with default distro
|
|
- Select additional distros
|
|
```
|
|
|
|
### Windows Path Considerations
|
|
|
|
**Path Formats:**
|
|
```bash
|
|
# Forward slashes (recommended, works everywhere)
|
|
docker run -v C:/Users/name/project:/app myimage
|
|
|
|
# Backslashes (need escaping in some contexts)
|
|
docker run -v C:\Users\name\project:/app myimage
|
|
|
|
# In docker-compose.yml (forward slashes)
|
|
volumes:
|
|
- C:/Users/name/project:/app
|
|
|
|
# Or relative paths
|
|
volumes:
|
|
- ./src:/app/src
|
|
```
|
|
|
|
### Git Bash / MINGW Path Conversion Issues
|
|
|
|
**CRITICAL ISSUE:** When using Docker in Git Bash (MINGW) on Windows, automatic path conversion breaks volume mounts.
|
|
|
|
**The Problem:**
|
|
```bash
|
|
# What you type in Git Bash:
|
|
docker run -v $(pwd):/app myimage
|
|
|
|
# What Git Bash converts it to (BROKEN):
|
|
docker run -v C:\Program Files\Git\d\repos\project:/app myimage
|
|
```
|
|
|
|
**Solutions:**
|
|
|
|
**1. MSYS_NO_PATHCONV (Recommended):**
|
|
```bash
|
|
# Per-command fix
|
|
MSYS_NO_PATHCONV=1 docker run -v $(pwd):/app myimage
|
|
|
|
# Session-wide fix (add to ~/.bashrc)
|
|
export MSYS_NO_PATHCONV=1
|
|
|
|
# Function wrapper (automatic for all Docker commands)
|
|
docker() {
|
|
(export MSYS_NO_PATHCONV=1; command docker.exe "$@")
|
|
}
|
|
export -f docker
|
|
```
|
|
|
|
**2. Double Slash Workaround:**
|
|
```bash
|
|
# Use double leading slash to prevent conversion
|
|
docker run -v //c/Users/project:/app myimage
|
|
|
|
# Works with $(pwd) too
|
|
docker run -v //$(pwd):/app myimage
|
|
```
|
|
|
|
**3. Named Volumes (No Path Issues):**
|
|
```bash
|
|
# Named volumes work without any fixes
|
|
docker run -v my-data:/data myimage
|
|
```
|
|
|
|
**What Works Without Modification:**
|
|
- Docker Compose YAML files with relative paths
|
|
- Named volumes
|
|
- Network and image commands
|
|
- Container commands without volumes
|
|
|
|
**What Needs MSYS_NO_PATHCONV:**
|
|
- Bind mounts with `$(pwd)`
|
|
- Bind mounts with absolute Unix-style paths
|
|
- Volume mounts specified on command line
|
|
|
|
**Shell Detection:**
|
|
```bash
|
|
# Detect Git Bash/MINGW and auto-configure
|
|
if [ -n "$MSYSTEM" ] || [[ "$(uname -s)" == MINGW* ]]; then
|
|
export MSYS_NO_PATHCONV=1
|
|
echo "Git Bash detected - Docker path conversion fix enabled"
|
|
fi
|
|
```
|
|
|
|
**Recommended ~/.bashrc Configuration:**
|
|
```bash
|
|
# Docker on Git Bash fix
|
|
if [ -n "$MSYSTEM" ]; then
|
|
export MSYS_NO_PATHCONV=1
|
|
fi
|
|
```
|
|
|
|
See the `docker-git-bash-guide` skill for comprehensive path conversion documentation, troubleshooting, and examples.
|
|
|
|
### Windows File Sharing
|
|
|
|
**Configure Shared Drives:**
|
|
```
|
|
Docker Desktop → Settings → Resources → File Sharing
|
|
Add: C:\, D:\, etc.
|
|
```
|
|
|
|
**Performance Considerations:**
|
|
- File sharing is slower than Linux/Mac
|
|
- Use WSL2 backend for better performance
|
|
- Store frequently accessed files in WSL2 filesystem
|
|
|
|
### Windows Line Endings
|
|
|
|
**Problem:** CRLF vs LF line endings
|
|
|
|
**Solution:**
|
|
```bash
|
|
# Git configuration
|
|
git config --global core.autocrlf input
|
|
|
|
# Or per-repo (.gitattributes)
|
|
* text=auto
|
|
*.sh text eol=lf
|
|
*.bat text eol=crlf
|
|
```
|
|
|
|
```dockerfile
|
|
# In Dockerfile for scripts
|
|
FROM alpine
|
|
COPY --chmod=755 script.sh /
|
|
# Ensure LF endings
|
|
RUN dos2unix /script.sh || sed -i 's/\r$//' /script.sh
|
|
```
|
|
|
|
### Windows Firewall
|
|
|
|
```powershell
|
|
# Allow Docker Desktop
|
|
New-NetFirewallRule -DisplayName "Docker Desktop" -Direction Inbound -Program "C:\Program Files\Docker\Docker\Docker Desktop.exe" -Action Allow
|
|
|
|
# Check blocked ports
|
|
netstat -ano | findstr :PORT
|
|
```
|
|
|
|
### Windows-Specific Docker Commands
|
|
|
|
```powershell
|
|
# Run PowerShell in container
|
|
docker run -it mcr.microsoft.com/powershell:lts-7.4-windowsservercore-ltsc2022
|
|
|
|
# Windows container example
|
|
docker run -it mcr.microsoft.com/windows/servercore:ltsc2022 cmd
|
|
|
|
# Check container type
|
|
docker info | Select-String "OSType"
|
|
```
|
|
|
|
### WSL2 Disk Management
|
|
|
|
**Problem:** WSL2 VHDX grows but doesn't shrink
|
|
|
|
**Solution:**
|
|
```powershell
|
|
# Stop Docker Desktop and WSL
|
|
wsl --shutdown
|
|
|
|
# Compact disk image (run as Administrator)
|
|
# Method 1: Optimize-VHD (requires Hyper-V tools)
|
|
Optimize-VHD -Path "$env:LOCALAPPDATA\Docker\wsl\data\ext4.vhdx" -Mode Full
|
|
|
|
# Method 2: diskpart
|
|
diskpart
|
|
# In diskpart:
|
|
select vdisk file="C:\Users\YourName\AppData\Local\Docker\wsl\data\ext4.vhdx"
|
|
attach vdisk readonly
|
|
compact vdisk
|
|
detach vdisk
|
|
exit
|
|
```
|
|
|
|
### Windows Development Workflow
|
|
|
|
```yaml
|
|
# docker-compose.yml for Windows
|
|
version: '3.8'
|
|
|
|
services:
|
|
app:
|
|
build: .
|
|
volumes:
|
|
# Use forward slashes
|
|
- ./src:/app/src
|
|
# Named volumes for better performance
|
|
- node_modules:/app/node_modules
|
|
ports:
|
|
- "3000:3000"
|
|
environment:
|
|
- NODE_ENV=development
|
|
# Windows-specific: ensure proper line endings
|
|
command: sh -c "dos2unix /app/scripts/*.sh && npm start"
|
|
|
|
volumes:
|
|
node_modules:
|
|
```
|
|
|
|
### Common Windows Issues
|
|
|
|
**Problem:** Permission denied errors
|
|
**Solution:**
|
|
```powershell
|
|
# Run Docker Desktop as Administrator
|
|
# Or grant permissions to Docker Desktop
|
|
icacls "C:\ProgramData\DockerDesktop" /grant Users:F /T
|
|
```
|
|
|
|
**Problem:** Slow performance
|
|
**Solution:**
|
|
- Use WSL2 backend
|
|
- Store project in WSL2 filesystem (`\\wsl$\Ubuntu\home\user\project`)
|
|
- Use named volumes for node_modules, etc.
|
|
|
|
**Problem:** Path not found
|
|
**Solution:**
|
|
- Use forward slashes
|
|
- Ensure drive is shared in Docker Desktop
|
|
- Use absolute paths or `${PWD}`
|
|
|
|
## Platform Comparison
|
|
|
|
| Feature | Linux | macOS | Windows |
|
|
|---------|-------|-------|---------|
|
|
| **Performance** | Excellent (native) | Good (VM overhead) | Good (WSL2) to Fair (Hyper-V) |
|
|
| **File sharing** | Native | Slow (improving with VirtioFS) | Slow (better in WSL2) |
|
|
| **Resource efficiency** | Best | Good | Good (WSL2) |
|
|
| **Feature set** | Complete | Complete | Complete (LCOW) |
|
|
| **Production** | Standard | Dev only | Dev only (LCOW) |
|
|
| **Ease of use** | Moderate | Easy (Docker Desktop) | Easy (Docker Desktop) |
|
|
| **Cost** | Free | Free (Docker Desktop Personal) | Free (Docker Desktop Personal) |
|
|
|
|
## Cross-Platform Best Practices
|
|
|
|
### Multi-Platform Images
|
|
|
|
```bash
|
|
# Create buildx builder
|
|
docker buildx create --name multiplatform --driver docker-container --use
|
|
|
|
# Build for multiple platforms
|
|
docker buildx build \
|
|
--platform linux/amd64,linux/arm64,linux/arm/v7 \
|
|
-t myimage:latest \
|
|
--push \
|
|
.
|
|
```
|
|
|
|
### Platform-Agnostic Dockerfiles
|
|
|
|
```dockerfile
|
|
# Works on all platforms
|
|
FROM node:20-alpine
|
|
|
|
# Use COPY with --chmod (not RUN chmod, which is slower)
|
|
COPY --chmod=755 script.sh /usr/local/bin/
|
|
|
|
# Use environment variables for paths
|
|
ENV APP_HOME=/app
|
|
WORKDIR ${APP_HOME}
|
|
|
|
# Use exec form for CMD/ENTRYPOINT (works on Windows containers too)
|
|
CMD ["node", "server.js"]
|
|
```
|
|
|
|
### Cross-Platform Compose Files
|
|
|
|
```yaml
|
|
version: '3.8'
|
|
|
|
services:
|
|
app:
|
|
build: .
|
|
volumes:
|
|
# Relative paths work everywhere
|
|
- ./src:/app/src
|
|
# Named volumes (platform-agnostic)
|
|
- data:/app/data
|
|
environment:
|
|
# Use environment variables
|
|
- NODE_ENV=${NODE_ENV:-development}
|
|
|
|
volumes:
|
|
data:
|
|
```
|
|
|
|
### Testing Across Platforms
|
|
|
|
```bash
|
|
# Test on different platforms with buildx
|
|
docker buildx build --platform linux/amd64 -t myapp:amd64 --load .
|
|
docker run --rm myapp:amd64
|
|
|
|
docker buildx build --platform linux/arm64 -t myapp:arm64 --load .
|
|
docker run --rm myapp:arm64
|
|
```
|
|
|
|
## Platform Selection Guide
|
|
|
|
**Choose Linux for:**
|
|
- Production deployments
|
|
- Maximum performance
|
|
- Full Docker feature set
|
|
- Minimal overhead
|
|
- CI/CD pipelines
|
|
|
|
**Choose macOS for:**
|
|
- Development on Mac hardware
|
|
- When you need macOS tools
|
|
- Docker Desktop ease of use
|
|
- M1/M2/M3 development
|
|
|
|
**Choose Windows for:**
|
|
- Development on Windows hardware
|
|
- Windows-specific applications
|
|
- When team uses Windows
|
|
- WSL2 for better Linux container support
|
|
|
|
This platform guide covers the major differences. Always test on your target deployment platform before going to production.
|