The integration of private container registries within a K3s environment is a critical architectural requirement for production-grade deployments. In enterprise settings, the reliance on public repositories like Docker Hub is often untenable due to security constraints, such as the need to keep proprietary images off public repositories, or performance bottlenecks where wide-area network latency increases image pull times. K3s addresses these challenges by providing a mechanism to configure containerd—its embedded container runtime—via a specific configuration file located at /etc/rancher/k3s/registries.yaml. This file allows operators to define mirrors, manage authentication credentials, and configure Transport Layer Security (TLS) settings. Because K3s utilizes an embedded containerd instance, the registries.yaml file serves as the primary interface for translating high-level registry requirements into the low-level configuration that containerd requires to pull images.
The Registry Configuration Architecture
K3s implements its registry management by checking for the existence of the /etc/rancher/k3s/registries.yaml file upon startup. If this file is present, K3s uses the definitions contained within to generate the corresponding containerd configuration. This architecture ensures that registry settings are decoupled from the main K3s service configuration, allowing for easier updates and node-specific adjustments.
The deployment of this file is not centralized; it must exist on every single node in the cluster that is required to pull images from a private registry. This includes both server nodes and agent nodes. A common oversight in cluster administration is neglecting the server nodes. Since server nodes are schedulable by default, if they have not been explicitly tainted to prevent workloads from running on them, they will attempt to pull images for any pods scheduled to them. Consequently, the absence of registries.yaml on a server node will lead to image pull failures if the requested image resides in a private repository.
Implementation of the Registries.yaml File
The /etc/rancher/k3s/registries.yaml file is the central point of configuration for all image retrieval logic. It supports several key sections: mirrors, configs, and authentication.
To create or update this configuration, administrators typically use a command that writes directly to the file system. An example of a basic configuration involves mirroring docker.io to a private endpoint while providing authentication and TLS certificates.
```bash mirrors: "docker.io": "registry.example.com": ca_file: "/etc/rancher/k3s/registry-ca.crt" Once this file is placed on the node, the K3s service must be restarted to apply the changes. The specific command depends on the role of the node: Mirrors are used to redirect requests for images from a public registry to a private endpoint. When a mirror is configured for Containerd employs an implicit "default endpoint" for all registries. This default endpoint acts as a safety net and is always tried as a last resort, regardless of whether other endpoints are listed in the It is important to note that rewrites are not applied to pulls against the default endpoint. Furthermore, if an administrator wishes to completely prevent containerd from attempting to reach the default registry endpoint, the node must be started with the Security for private registries is managed through the For registries using custom CA certificates, the certificate must be present on the K3s node. The certificate can be transferred from the registry server using secure copy: The configuration in In high-security environments, Mutual TLS (mTLS) may be required. This involves providing not only the CA certificate but also a client certificate and a private key to authenticate the K3s node to the registry. For development environments where TLS is not implemented, K3s allows the skipping of TLS verification. This is achieved by setting the A pull-through cache is a specialized registry that caches images from an upstream source (like Docker Hub) to reduce bandwidth and speed up subsequent pulls. To deploy a simple pull-through cache, a Docker Compose file can be used to run the registry image with specific environment variables for proxying. ```yaml services: After deploying the cache, K3s must be configured to use this internal endpoint as a mirror for ```yaml mirrors: When deploying applications that use images from a private registry, the standard Kubernetes Deployment manifest is used. Because the authentication is handled at the containerd level via ```yaml apiVersion: apps/v1 In air-gapped environments, system images (such as the pause image) must be manually mirrored to a private registry. This process requires a host with Docker or similar tooling. The workflow for mirroring is as follows: Since K3s does not include a built-in local registry plugin, a Docker registry can be installed as a service within the cluster and exposed via the default Traefik ingress on ports 80 and 443. The setup involves creating a dedicated namespace and applying a registry manifest: To ensure that tools like Docker or Podman can push to this local insecure registry, specific configurations must be applied: When an image pull fails with a "no basic auth credentials" error, the investigation must focus on the node where the pod was scheduled. This can be identified using: Once the node is identified, the following troubleshooting steps should be performed: A critical point of failure occurs when users attempt to use If a system is configured with the Furthermore, it is important to distinguish between a container runtime and a registry. Containerd possesses an image store, but it does not function as an image registry that other nodes can pull from. For nodes to share images, a separate local image registry must be established, or the environment must wait for the implementation of peer-to-peer mesh image sharing. A complete production configuration for ```yaml mirrors: "docker.io": "registry.internal.example.com": "docker-mirror.internal.example.com": "registry.internal.example.com": The management of private registries in K3s is a multifaceted process that hinges on the correct implementation of the
sudo tee /etc/rancher/k3s/registries.yaml > /dev/null <registries.yaml - K3s private registry configuration
Try your private mirror first for docker.io pulls
endpoint:
- "https://registry.example.com"
configs:Authentication for the private registry
auth:
username: "admin"
password: "RegistryPassword"
tls:CA certificate for the registry's TLS certificate
EOF
```
sudo systemctl restart k3ssudo systemctl restart k3s-agentUnderstanding Mirror Configuration and Fallback Logic
docker.io, containerd will attempt to pull the image from the specified endpoint first.registries.yaml file. For example, the default endpoint for docker.io is https://index.docker.io/v2. If a pull request is made for registry.example.com:5000/rancher/mirrored-pause:3.6, containerd will eventually fall back to https://registry.example.com:5000/v2.--disable-default-registry-endpoint flag.Advanced TLS and Authentication Strategies
configs section of the registries.yaml file. Depending on the security requirements of the environment, several levels of TLS configuration are available.Certificate Authority (CA) Integration
bash
scp registry-server:/etc/ssl/certs/registry-ca.crt /etc/rancher/k3s/registry-ca.crt
registries.yaml then points to this file:yaml
configs:
"registry.example.com:5000":
tls:
ca_file: "/etc/rancher/k3s/registry-ca.crt"
Mutual TLS (mTLS) Configuration
yaml
configs:
"registry.example.com":
tls:
ca_file: "/etc/rancher/k3s/registry-ca.crt"
cert_file: "/etc/rancher/k3s/registry-client.crt"
key_file: "/etc/rancher/k3s/registry-client.key"
Insecure Registry Handling
insecure_skip_verify flag to true.yaml
configs:
"registry.example.com:5000":
tls:
insecure_skip_verify: true
Pull-Through Cache Implementation
docker-compose.yml for a pull-through cache
docker-cache:
image: registry:3
ports:
- "5000:5000"
environment:
REGISTRYPROXYREMOTEURL: https://registry-1.docker.io
REGISTRYPROXYUSERNAME: your-docker-hub-username
REGISTRYPROXYPASSWORD: your-docker-hub-pat
volumes:
- /opt/docker-cache:/var/lib/registry
restart: always
```docker.io:registries.yaml
"docker.io":
endpoint:
- "http://docker-cache.internal:5000"
```Private Registry Image Deployment Workflow
registries.yaml, there is no need to define imagePullSecrets within the pod specification.deployment with private image
kind: Deployment
metadata:
name: private-app
spec:
replicas: 2
selector:
matchLabels:
app: private-app
template:
metadata:
labels:
app: private-app
spec:
containers:
- name: app
# This image will be pulled from the private registry
image: registry.internal.example.com/myapp:1.0
ports:
- containerPort: 8080
```Mirroring K3s System Images for Air-Gapped Environments
k3s-images.txt file from the official GitHub repository for the specific release version.
docker pull docker.io/rancher/mirrored-pause:3.6
docker tag docker.io/rancher/mirrored-pause:3.6 registry.example.com:5000/rancher/mirrored-pause:3.6
docker push registry.example.com:5000/rancher/mirrored-pause:3.6Local Registry Installation within K3s
bash
kubectl create namespace docker-registry
kubectl apply -f docker-registry.yaml -n docker-registry
http://registry.localhost as an insecure registry in the Docker daemon settings.--tls-verify=false flag during the push:
podman push --tls-verify=false registry.localhost/test:latestTroubleshooting Registry Failures
bash
kubectl get pod -o wide -n NAMESPACE POD
sudo cat /etc/rancher/k3s/registries.yaml
sudo tail -n 100 /var/lib/rancher/k3s/agent/containerd/containerd.log
sudo systemctl restart k3sRuntime Integration and Constraints
registries.yaml while utilizing a container runtime provided by the host Linux distribution rather than the embedded containerd. The registries.yaml support is exclusive to the embedded containerd.--container-runtime-endpoint flag to use an external containerd, the registries.yaml file will be ignored. To resolve this, the external containerd must be uninstalled, the flag removed from the K3s startup command, and the embedded containerd restored.Comparison of Registry Configuration Methods
Feature
Public Registry
Private Registry (Direct)
Pull-Through Cache
Local Registry (In-Cluster)
Configuration File
None required
registries.yamlregistries.yamlregistries.yaml
Auth Method
Public/PAT
Basic Auth / mTLS
Proxy Credentials
Insecure / Local TLS
Pull Speed
Network Dependent
High (Internal)
High (Cached)
Ultra-High (Local)
Security
Low (Public)
High (Private)
Medium (Cached)
Medium (Local)
Use Case
General
Proprietary Apps
Bandwidth Saving
Dev/Test
Production-Grade Configuration Summary
registries.yaml often combines internal mirrors for public images and direct connections to company-specific registries./etc/rancher/k3s/registries.yaml - Production configuration
Try the internal mirror first for docker.io pulls
endpoint:
- "https://docker-mirror.internal.example.com"Internal registry for company images
endpoint:
- "https://registry.internal.example.com"
configs:Internal mirror authentication
auth:
username: "k3s-puller"
password: "SecurePullPassword"
tls:
ca_file: "/etc/rancher/k3s/internal-ca.crt"Private company registry
auth:
username: "k3s-puller"
password: "SecurePullPassword"
tls:
cafile: "/etc/rancher/k3s/internal-ca.crt"
certfile: "/etc/rancher/k3s/k3s-client.crt"
key_file: "/etc/rancher/k3s/k3s-client.key"
```Conclusion
/etc/rancher/k3s/registries.yaml file. By leveraging mirrors, administrators can optimize the retrieval of public images, while the configs section allows for the secure integration of proprietary image repositories through Basic Auth and mTLS. The architecture emphasizes the importance of node-level consistency, as every schedulable node must possess the configuration to ensure successful pod deployment. While the embedded containerd simplifies this process, the operator must remain vigilant about the distinction between image stores and registries, and ensure that the container runtime is correctly aligned with K3s's embedded logic. Ultimately, the ability to transition from insecure development registries to hardened, production-grade mTLS configurations allows K3s to scale from small lab environments to secure, air-gapped enterprise infrastructures.Sources