containerd Configuration

Master containerd configuration for production environments. Learn to configure the CRI plugin, registry mirrors, snapshot drivers, and performance tuning parameters.

config.toml CRI Plugin Registry
containerd Configuration Overview

containerd is configured using a TOML file located at `/etc/containerd/config.toml`. This file controls every aspect of containerd's behavior: from basic settings like logging and storage paths to advanced plugin configurations for the CRI (Container Runtime Interface), snapshot drivers, and registry mirrors.

Proper configuration is essential for production environments. The default configuration works for development, but for production you'll need to tune settings like cgroup management, image pull behavior, and registry authentication. This guide covers the most important configuration options.

Always backup your configuration before making changes: `sudo cp /etc/containerd/config.toml /etc/containerd/config.toml.bak`
Generating Default Configuration
# Generate default configuration sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml # View current configuration containerd config dump # Validate configuration containerd config validate # Test configuration sudo containerd --config /etc/containerd/config.toml --log-level debug
Basic Configuration Options
# Basic config.toml structure version = 2 # Root directory for containerd state root = "/var/lib/containerd" # State directory state = "/run/containerd" # Log level (trace, debug, info, warn, error, fatal, panic) log_level = "info" # Log format (text or json) log_format = "text" # Disable plugins disabled_plugins = [] # Required plugins (empty means all enabled) required_plugins = []
CRI Plugin Configuration (Kubernetes)

The CRI plugin is the most important configuration for Kubernetes nodes. It controls how containerd interacts with kubelet.

# CRI plugin configuration [plugins."io.containerd.grpc.v1.cri"] # Pause image (sandbox container) sandbox_image = "registry.k8s.io/pause:3.9" # Max log line size max_container_log_line_size = 16384 # Cgroup driver for kubelet [plugins."io.containerd.grpc.v1.cri".cgroup] # Path to cgroup for pods path = "/" # containerd settings [plugins."io.containerd.grpc.v1.cri".containerd] # Default runtime default_runtime_name = "runc" # Snapshotter snapshotter = "overlayfs" # 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] # Use systemd cgroups SystemdCgroup = true # Image pulling settings [plugins."io.containerd.grpc.v1.cri".containerd] # Pull image timeout image_pull_progress_timeout = "120s" # Image pull behavior # Valid values: always, missing, never image_pull_behavior = "missing"
The `SystemdCgroup = true` setting is critical for cgroup v2 compatibility. Without it, resource limits may not work correctly.
Registry Configuration

Configure registry mirrors, authentication, and TLS settings for pulling images from private registries.

# Registry configuration [plugins."io.containerd.grpc.v1.cri".registry] # Path to registry configuration directory config_path = "/etc/containerd/certs.d" # Registry mirrors [plugins."io.containerd.grpc.v1.cri".registry.mirrors] [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] endpoint = ["https://registry-1.docker.io"] [plugins."io.containerd.grpc.v1.cri".registry.mirrors."myregistry.azurecr.io"] endpoint = ["https://myregistry.azurecr.io"] # Auth configuration [plugins."io.containerd.grpc.v1.cri".registry.configs."myregistry.azurecr.io".auth] username = "myuser" password = "mypassword" # TLS configuration [plugins."io.containerd.grpc.v1.cri".registry.configs."myregistry.azurecr.io".tls] insecure_skip_verify = false ca_file = "/etc/containerd/certs.d/ca.crt"
For enterprise environments, use `config_path` to manage registry configurations in separate files, making it easier to update without restarting containerd.
Snapshotter Configuration
# Snapshotter configuration [plugins."io.containerd.snapshotter.v1.overlayfs"] root_path = "/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs" # For ZFS [plugins."io.containerd.snapshotter.v1.zfs"] root_path = "/var/lib/containerd/io.containerd.snapshotter.v1.zfs" # For native (copy-based) [plugins."io.containerd.snapshotter.v1.native"] root_path = "/var/lib/containerd/io.containerd.snapshotter.v1.native"
Runtime Configuration
# Runtime configuration [plugins."io.containerd.runtime.v2.task"] # Platform-specific settings [plugins."io.containerd.runtime.v2.task".platforms] [plugins."io.containerd.runtime.v2.task".platforms.linux] # Runtime root directory root = "/run/containerd/runtime/v2/task" # Logging configuration [plugins."io.containerd.runtime.v2.task".options] # Enable debug logging for runtime debug = false
Metrics and Monitoring
# Metrics configuration [metrics] # Address to serve metrics on address = "0.0.0.0:1338" # Enable metrics enabled = true # Metrics path [metrics.prometheus] # Enable Prometheus metrics enabled = true
Enable metrics to monitor containerd performance and resource usage. Prometheus metrics are available at `http://localhost:1338/metrics`.
Logging Configuration
# Global logging log_level = "info" log_format = "text" # CRI plugin logging [plugins."io.containerd.grpc.v1.cri"] # Additional logging for CRI stream_server_address = "127.0.0.1" stream_server_port = "0" [plugins."io.containerd.grpc.v1.cri".cgroup] # Log cgroup operations path = "/" # Runtime logging [plugins."io.containerd.runtime.v2.task".options] # Enable debug logging debug = false
Advanced Configuration Options

Timeouts

image_pull_progress_timeout = "120s"
shutdown_timeout = "15s"

Storage

root = "/var/lib/containerd"
state = "/run/containerd"

Plugins

disabled_plugins = []
required_plugins = []

Security

pod_security_policy = ""
seccomp_profile = ""
Applying Configuration Changes
# Validate configuration containerd config validate # Test configuration sudo containerd --config /etc/containerd/config.toml --log-level debug # Restart containerd sudo systemctl restart containerd # Check status sudo systemctl status containerd # Verify configuration is loaded containerd config dump | grep -A 10 "cri"
Always validate configuration before restarting. A syntax error can prevent containerd from starting, causing cluster downtime.
Common Configuration Scenarios
# Scenario 1: Use registry mirror for Docker Hub [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] endpoint = ["https://mirror.gcr.io", "https://registry-1.docker.io"] # Scenario 2: Configure private registry with auth [plugins."io.containerd.grpc.v1.cri".registry.configs."myregistry.azurecr.io".auth] auth = "base64_encoded_credentials" # Scenario 3: Use ZFS snapshotter snapshotter = "zfs" [plugins."io.containerd.snapshotter.v1.zfs"] root_path = "/var/lib/containerd/zfs" # Scenario 4: Disable unnecessary plugins disabled_plugins = ["io.containerd.snapshotter.v1.devicemapper"]
Frequently Asked Questions
Where is the containerd configuration file?
The default location is `/etc/containerd/config.toml`. You can specify a different location with the `--config` flag when starting containerd.
How do I reload configuration without restarting containerd?
containerd does not support hot reload. You must restart the service for configuration changes to take effect. This is why validation is important before restarting.
What's the difference between root and state directories?
`root` stores persistent data (images, snapshots). `state` stores runtime data (sockets, PID files). Root persists across reboots; state is ephemeral.
How do I configure containerd for a private registry?
Add the registry to `registry.mirrors` and configure authentication in `registry.configs`. You can also use `config_path` to manage multiple registries.
What is the pause image and why is it important?
The pause container holds the network namespace for each pod. It's a minimal container that runs in every pod. The sandbox_image setting specifies which pause image to use.
How do I enable debug logging?
Set `log_level = "debug"` in the config.toml and restart containerd. For more verbose logging, use `--log-level debug` when starting containerd.
Can I use containerd without the CRI plugin?
Yes! containerd can be used as a standalone runtime without CRI. For Kubernetes, you need the CRI plugin enabled. For Docker, it uses containerd without CRI.
How do I check which configuration containerd is using?
Run `containerd config dump` to see the active configuration. This shows the merged configuration with all defaults applied.
Previous: containerd vs CRI-O Next: containerd Logging

Proper configuration is essential for production containerd deployments. Use these settings as a starting point and adjust based on your specific requirements.