containerd Production Deployment Guide
A comprehensive guide to deploying containerd in production environments. Learn best practices for configuration, monitoring, security, performance optimization, and operational considerations for enterprise-grade container infrastructure.
Deploying containerd in production is fundamentally different from development or testing environments. Production workloads demand high availability, performance, security, and operational excellence. A poorly configured containerd deployment can lead to:
- Downtime - Failed container starts or image pulls causing application outages
- Performance degradation - Slow container startup times affecting user experience
- Security breaches - Container escapes or unauthorized access due to misconfiguration
- Resource exhaustion - Disk space filling up, causing node failures
- Operational overhead - Constant firefighting and manual interventions
/var/lib/containerd. Consider using SSD storage for better I/O performance. Plan for growth—monitor usage and scale storage proactively.containerd config default > /etc/containerd/config.toml and modify settings. Always validate with containerd config validate before restarting.SystemdCgroup = true for cgroup v2 compatibility. Configure the pause image, snapshotter (overlayfs recommended), and default runtime. Ensure the CRI plugin is enabled for Kubernetes integration.config_path for managing multiple registry configurations.logrotate or configure the CRI plugin's max_container_log_line_size. Set up centralized log shipping for operational visibility.Here's a production-ready config.toml with all essential settings and explanations:
# /etc/containerd/config.toml - Production Configuration
version = 2
# Storage paths - use SSD for /var/lib/containerd
root = "/var/lib/containerd"
state = "/run/containerd"
# Logging - info level for production, debug only for troubleshooting
log_level = "info"
log_format = "text" # or "json" for structured logging
# Disable unused plugins to reduce attack surface
disabled_plugins = ["io.containerd.snapshotter.v1.devicemapper"]
# CRI Plugin Configuration
[plugins."io.containerd.grpc.v1.cri"]
# Sandbox image - use specific version, not latest
sandbox_image = "registry.k8s.io/pause:3.9"
# Max container log line size - prevents log explosion
max_container_log_line_size = 16384
# Cgroup configuration - REQUIRED for cgroup v2
[plugins."io.containerd.grpc.v1.cri".cgroup]
path = "/"
# containerd runtime settings
[plugins."io.containerd.grpc.v1.cri".containerd]
default_runtime_name = "runc"
snapshotter = "overlayfs" # Best performance
# Pull timeout - adjust based on image sizes
image_pull_progress_timeout = "120s"
image_pull_behavior = "missing" # Only pull when missing
# Runtime configuration
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
# CRITICAL: SystemdCgroup must be true for cgroup v2
SystemdCgroup = true
# Registry Configuration
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d" # For separate registry configs
# Registry mirrors for Docker Hub
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://mirror.gcr.io", "https://registry-1.docker.io"]
# Metrics Configuration
[metrics]
address = "0.0.0.0:1338"
enabled = true
[metrics.prometheus]
enabled = true
# Garbage Collection Configuration
[plugins."io.containerd.gc.v1.scheduler"]
# Schedule GC every 5 minutes
schedule = "*/5 * * * *"
pause_duration = "1s"
SystemdCgroup = true setting is mandatory on modern Linux distributions with cgroup v2. Without this, resource limits won't work correctly, and containers may fail to start. Always verify your cgroup version with mount | grep cgroup2.
Storage Optimization
/var/lib/containerd and allocate at least 50-100GB per node.
Why: Container operations are I/O intensive. SSD storage significantly improves image pull times, container startup times, and overall performance. Insufficient disk space leads to node pressure, pod evictions, and application failures.
Monitor: Set up alerts at 80% disk usage and configure automatic cleanup.
Registry Optimization
Why: Registry mirrors reduce latency, avoid rate limits, and improve reliability. A private registry cache (like Harbor or JFrog) can significantly speed up image pulls in enterprise environments.
Implementation: Use
config_path for per-registry configuration. Test mirror endpoints for availability.
Security Hardening
Why: Defense in depth. seccomp limits syscalls, MAC policies restrict file and network access, and image signing prevents supply chain attacks. These controls reduce the impact of container escapes.
Implementation: Start with default profiles, then customize based on workload requirements. Test thoroughly in staging.
Observability
Why: You can't improve what you can't measure. Metrics provide visibility into performance trends, logs help debug issues, and tracing shows request flows through the system.
Implementation: Use Prometheus for metrics, ELK/Loki for logs, and Jaeger for tracing. Set up dashboards and alerts for key metrics.
Automated Cleanup
Why: Accumulated images and snapshots consume disk space and degrade performance. Automated cleanup prevents disk pressure and reduces operational overhead.
Implementation: Use cron jobs for
ctr image prune --keep=10, ctr snapshot prune, and ctr content prune. Configure Kubernetes image GC for automatic cleanup.
Version Management
Why: Uncontrolled updates can introduce breaking changes or performance regressions. Testing ensures compatibility and prevents surprises in production.
Implementation: Use package managers with version pinning. Document upgrade procedures. Maintain a rollback plan for each upgrade.
A comprehensive monitoring strategy is essential for production containerd deployments. Here are the key metrics to monitor and how to set them up:
Disk Usage Metrics
# Key disk metrics to monitor
- /var/lib/containerd usage percentage
- Inode usage (critical for large numbers of small files)
- Snapshot directory size
- Content store size
- Log directory size
# Prometheus queries
node_filesystem_avail_bytes{mountpoint="/var/lib/containerd"}
node_filesystem_size_bytes{mountpoint="/var/lib/containerd"}
node_filesystem_files_avail{mountpoint="/var/lib/containerd"}
Performance Metrics
# Container operation metrics
container_runtime_operations_total
container_runtime_operations_errors_total
container_runtime_operations_duration_seconds
# Image pull metrics
container_image_pull_duration_seconds
container_image_pull_count
# Container resource usage
container_memory_usage_bytes
container_cpu_usage_seconds_total
Alerting Rules
# Critical alerts
- Disk usage > 85%: Immediate action required
- Container operation error rate > 5%: Service degradation
- Image pull duration > 60s: Network or registry issues
- Container restart count > 5 in 10m: Application instability
# Alertmanager configuration example
groups:
- name: containerd_alerts
rules:
- alert: ContainerDiskUsageHigh
expr: (1 - (node_filesystem_avail_bytes{mountpoint="/var/lib/containerd"} / node_filesystem_size_bytes{mountpoint="/var/lib/containerd"})) * 100 > 85
annotations:
summary: "containerd disk usage is critical ({{ $value }}%)"
runbook: "https://wiki.example.com/containerd-disk-cleanup"
Restrict system calls to reduce attack surface
Enforce MAC policies for containers
Verify image integrity and origin
Use minimal capability sets
Reduce impact of container escapes
Track who accessed what and when
Only allow trusted registries
Restrict ingress/egress traffic
Apply security patches promptly
Use Trivy, Clair, or similar tools
Document these procedures for your team to ensure consistent and effective incident response:
Runbook: Disk Space Emergency
Immediate actions:
- Check disk usage:
df -h /var/lib/containerd - Prune images:
ctr image prune --keep=5 -f - Prune snapshots:
ctr snapshot prune -f - Prune content:
ctr content prune -f - Check logs:
journalctl -u containerd -n 50
Prevention: Schedule regular cleanup, monitor disk usage, configure Kubernetes image GC.
Runbook: Image Pull Failures
Diagnostic steps:
- Check containerd logs:
journalctl -u containerd | grep -i pull - Test connectivity:
curl -v https://registry-1.docker.io/v2/ - Check DNS:
nslookup registry-1.docker.io - Verify credentials: Check config.toml registry auth
- Test with ctr:
ctr image pull --debug <image>
Escalation: If issue persists, check network firewall, proxy settings, or registry status.
Runbook: Container Startup Failures
Diagnostic steps:
- Check container logs:
crictl logs <container-id> - Check containerd logs:
journalctl -u containerd -f - Verify runtime:
runc --version - Check cgroups:
cat /proc/self/cgroup - Check SELinux/AppArmor:
sestatusorsudo aa-status
Common fixes: Set
SystemdCgroup = true, disable SELinux temporarily for testing, increase memory limits.
/var/lib/containerd. For large deployments with many images, 100GB or more is recommended. Monitor usage patterns to determine the right size. Always have a cleanup strategy in place.runc with SystemdCgroup = true. This gives you the best of both worlds: runc's stability and systemd's cgroup management. For cgroup v2, this is the only supported configuration.log_level = "info" (not debug). Configure log_format = "json" for structured logging. Set up log rotation to prevent disk exhaustion. Forward logs to a central logging system (ELK, Loki) for analysis and debugging.A well-planned containerd production deployment is the foundation of reliable container infrastructure. Follow these best practices, monitor continuously, and iterate based on operational experience.