Przejdź do treści
Biblioteka skilli
DevOps i chmura · Planowanie

container-runtime-docker-containerd

/container-runtime-docker-containerd

Pomaga wybrać i skonfigurować silnik uruchomieniowy kontenerów: Docker Engine, containerd lub CRI-O, tryb rootless, runc, crun, gVisor i Kata oraz migrację klastrów po dockershim.

Licencja
Apache-2.0
Ostatnia zmiana repozytorium
28.07.2026

Ocena i bezpieczeństwo

100/ 100Klasa: dobry
Format25 / 25
Frontmatter z nazwą i opisem, poprawna nazwa, opis do 1024 znaków, nazwa zgodna z folderem.
Odkrywalność25 / 25
Opis mówi, kiedy użyć skilla, ma sensowną długość i jest w 3. osobie.
Treść35 / 35
Co najmniej 150 słów i do 500 linii, nagłówki, listy kroków, przykłady albo kod.
Higiena15 / 15
Bez zaślepek typu TODO, bez ścieżek Windows, z licencją.
Ryzykobrak sygnałów w skanie
Pliki w paczce
1
Skrypty
0
Komentarze HTML
0
Adresy URL w SKILL.md
4
Przestarzałość

Brak sygnałów. Repozytorium zmienione 28.07.2026, bez odwołań do wycofanych modeli i API.

Licencja

Apache-2.0, otwarta: można używać i zmieniać, z zachowaniem licencji i informacji o zmianach.

Co robi i kiedy

Pomaga wybrać i skonfigurować silnik uruchomieniowy kontenerów: Docker Engine, containerd lub CRI-O, tryb rootless, runc, crun, gVisor i Kata oraz migrację klastrów po dockershim.

Wyzwalacze z opisu

choose a container runtime for Kubernetes nodes,configure containerd,run containers rootless,migrate off Docker/dockershim,add a sandboxed/gVisor runtime class,
Oryginalny opis (EN)

Guides choosing and configuring the container RUNTIME engine — Docker Engine vs. containerd vs. CRI-O — including rootless mode, runtime (runc/crun/gVisor/Kata) configuration, and migration considerations for clusters moving off dockershim. This is about the runtime that executes containers, not building/tagging images. Use when a user asks to "choose a container runtime for Kubernetes nodes," "configure containerd," "run containers rootless," "migrate off Docker/dockershim," "add a sandboxed/gVisor runtime class," or "debug a CRI-level container start failure.

Jak działa

  1. Purpose
  2. When to use
  3. Prerequisites & environment
  4. Step-by-step guidance
  5. Best practices
  6. Common pitfalls
  7. Worked example
  8. Cross-references
Sekcje z nagłówków SKILL.md, w oryginale · 313 linii, 1 723 słów
Podgląd SKILL.md
---
name: container-runtime-docker-containerd
description: >
  Guides choosing and configuring the container RUNTIME engine — Docker
  Engine vs. containerd vs. CRI-O — including rootless mode, runtime
  (runc/crun/gVisor/Kata) configuration, and migration considerations
  for clusters moving off dockershim. This is about the runtime that
  executes containers, not building/tagging images. Use when a user
  asks to "choose a container runtime for Kubernetes nodes," "configure
  containerd," "run containers rootless," "migrate off Docker/dockershim,"
  "add a sandboxed/gVisor runtime class," or "debug a CRI-level
  container start failure."
license: Apache-2.0
compatibility: "Claude Code, GitHub Copilot, OpenAI Codex, Cursor, Gemini CLI"
metadata:
  domain: kubernetes-platform
  maturity: stable
---

# Container Runtime: Docker Engine, containerd, CRI-O

## Purpose

The container runtime is the layer that actually creates namespaces,
cgroups, and processes for a container — it sits below the image build
process entirely and below Kubernetes's own scheduling logic. Since
Kubernetes 1.24 removed dockershim, every node runs a CRI-compliant
runtime directly (containerd or CRI-O), and Docker Engine itself is no
longer a supported *node* runtime for new clusters, though it remains
extremely relevant as a local development and image-build tool. Getting
runtime configuration wrong — rootful-by-default containers, a
misconfigured cgroup driver mismatching kubelet's, no sandboxing for
untrusted workloads — produces either broken node bootstrap or a real
container-escape risk. This skill covers the runtime engine layer;
building and tagging images is a separate concern (see
[container-build-and-release](../../../devops/skills/container-build-and-release/SKILL.md)).

## When to use

- Choosing the CRI runtime for new Kubernetes nodes (containerd vs.
  CRI-O) post-dockershim.
- Migrating an existing cluster off Docker Engine/dockershim to a
  CRI-native runtime.
- Configuring containerd (`config.toml`) — registry mirrors, cgroup
  driver, pull-through cache, private registry auth.
- Running containers rootless (no root-owned daemon, unprivileged user
  namespaces) for reduced host attack surface.
- Adding a sandboxed runtime class (gVisor, Kata Containers) for
  untrusted or multi-tenant workloads that need stronger isolation than
  standard `runc`.
- Debugging a container that fails to start with a CRI/runtime-level
  error rather than an application error (`OCI runtime create failed`,
  cgroup driver mismatch, missing seccomp profile).

## Prerequisites & environment

- containerd ≥ 1.7 (bundled with most current Kubernetes node images) or
  CRI-O matched exactly to the Kubernetes minor version being run —
  CRI-O version-locks to Kubernetes (CRI-O 1.30.x targets Kubernetes
  1.30) and does not support mixing minor versions the way containerd's
  versioning is decoupled from Kubernetes releases.
- `crictl` (the CRI-level equivalent of `docker`/`nerdctl` CLI) for
  debugging directly against whatever CRI runtime is in use, configured
  via `/etc/crictl.yaml` pointing at the correct runtime socket.
- Root/sudo on nodes to edit runtime configuration
  (`/etc/containerd/config.toml`, `/etc/crio/crio.conf.d/`) and restart
  the runtime service — this is a node-level, not workload-level,
  change and typically requires a node drain/cordon for a live cluster.
- Confirm the kubelet's configured `cgroupDriver` (`systemd` is the
  current recommended default) matches the runtime's own cgroup driver
  setting exactly — a mismatch is one of the most common node
  bootstrap failures.
- Docker Engine itself, if used at all in this context, is for local
  development/CI image builds (`docker build`), not as the Kubernetes
  node runtime — see
  [container-build-and-release](../../../devops/skills/container-build-and-release/SKILL.md)
  for that usage.

## Step-by-step guidance

1. **Choose containerd vs. CRI-O deliberately**:
   - **containerd**: the most widely used CRI runtime, backs Docker
     Engine itself under the hood, has the broadest ecosystem/tooling
     support (`nerdctl` for a Docker-CLI-like local experience), and is
     the default on most managed Kubernetes node images (EKS, GKE, AKS
     all ship containerd-based nodes).
   - **CRI-O**: purpose-built for Kubernetes only (no independent
     daemon use case outside a CRI context), version-locked to the
     Kubernetes release, and the default on OpenShift/ROSA nodes — see
     [openshift-and-rosa-platform](../openshift-and-rosa-platform/SKILL.md).
   For a self-managed cluster with no OpenShift/Red Hat requirement,
   containerd is the more broadly supported default; choose CRI-O
   primarily when the platform (OpenShift) mandates it or the team
   specifically wants its tighter Kubernetes-only scope.

2. **Confirm and align the cgroup driver** before/during node bootstrap
   — this is the single most common "node won't join" failure:
   ```toml
   # /etc/containerd/config.toml
   [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
     SystemdCgroup = true
   ```
   ```yaml
   # kubelet config must match
   cgroupDriver: systemd
   ```

3. **Configure a registry mirror/pull-through cache** to reduce
   external registry dependency and rate-limit exposure:
   ```toml
   # /etc/containerd/config.toml
   [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
     endpoint = ["https://mirror.internal.example.com", "https://registry-1.docker.io"]
   ```
   ```bash
   sudo systemctl restart containerd
   ```

4. **Configure private registry authentication** without embedding
   credentials in the config file directly where avoidable — use a
   credential helper or a separately-permissioned config path:
   ```toml
   [plugins."io.containerd.grpc.v1.cri".registry.configs."registry.internal.example.com".auth]
     auth = "${REGISTRY_AUTH_BASE64}"
   ```
   Prefer Kubernetes-native `imagePullSecrets` at the workload level for
   per-namespace registry credentials over node-wide containerd auth
   config wherever the credential scope should be workload-specific
   rather than node-wide.

5. **Debug directly at the CRI level** when a pod fails to start but
   `kubectl describe pod` doesn't give enough detail:
   ```bash
   sudo crictl ps -a
   sudo crictl logs <container-id>
   sudo crictl inspect <container-id>
   ```
   This bypasses kubelet's abstraction and shows exactly what the
   runtime attempted and why it failed (missing image, OCI spec
   error, seccomp/AppArmor profile rejection).

6. **Run rootless containers** where host attack-surface reduction is
   the priority (most relevant for standalone Docker/containerd use —
   e.g. CI runners — rather than typical Kubernetes node setups, which
   usually rely on Pod-level `securityContext.runAsNonRoot` and user
   namespaces instead):
   ```bash
   # rootless Docker (dockerd-rootless-setuptool.sh, bundled with Docker ≥ 20.10)
   dockerd-rootless-setuptool.sh install
   systemctl --user start docker
   ```
   ```bash
   # rootless containerd + nerdctl
   containerd-rootless-setuptool.sh install
   nerdctl run --rm alpine echo hello
   ```
   Kubernetes' own user-namespace support (stable since 1.30 via
   `hostUsers: false` on the PodSpec) provides an analogous benefit at
   the pod level without needing a fully rootless node daemon:
   ```yaml
   spec:
     hostUsers: false
   ```

7. **Add a sandboxed RuntimeClass** for workloads needing stronger
   isolation than default `runc` namespaces (untrusted code execution,
   hard multi-tenancy):
   ```yaml
   apiVersion: node.k8s.io/v1
   kind: RuntimeClass
   metadata: { name: gvisor }
   handler: runsc
   ```
   ```yaml
   spec:
     runtimeClassName: gvisor
   ```
   This requires the sandboxed runtime (gVisor's `runsc`, or Kata
   Containers) actually installed and registered with containerd/CRI-O
   on the node first (`containerd`'s `config.toml` needs a matching
   `runtimes.runsc` entry) — applying the `RuntimeClass` alone without
   the node-side handler installed leaves pods stuck in
   `CreateContainerError`.

8. **Migrate a cluster off Docker/dockershim**, if any node still runs
   it: since Kubernetes 1.24, dockershim no longer exists in-tree at
   all, so this is not an optional modernization but a hard requirement
   for any node still on ≤ 1.23 to upgrade past — drain each node,
   reprovision with a containerd/CRI-O-based node image (most managed
   Kubernetes offerings handle this automatically on node group/pool
   replacement), and rejoin:
   ```bash
   kubectl drain <node> --ignore-daemonsets --delete-emptydir-data
   # reprovision node with containerd-based image, then:
   kubectl uncordon <node>
   ```

## Best practices

- Match the kubelet and runtime cgroup drivers explicitly at every node
  provisioning step (bake it into the node image/bootstrap script), not
  as a manual per-node fix applied after nodes fail to join.
- Use `crictl`/`nerdctl` for node-level runtime debugging instead of
  reaching for a Docker Engine install "because it's familiar" — adding
  Docker Engine alongside the CRI runtime on a Kubernetes node is
  redundant, adds an unused daemon, and does not reflect what actually
  runs the pod's containers.
- Keep registry mirror/auth configuration in node bootstrap
  automation (Terraform user-data, a DaemonSet-applied config, or the
  node image itself), not manually edited on individual nodes — manual
  edits drift and don't survive node replacement.
- Reserve sandboxed runtimes (gVisor, Kata) for workloads that
  specifically need the added isolation — they carry a real performance
  and compatibility cost (syscall interception overhead for gVisor,
  full VM boundary for Kata) and are not a drop-in replacement for
  `runc` everywhere.
- Prefer Kubernetes-native `imagePullSecrets`/workload-level
  `securityContext` and user namespaces over node-wide rootless-daemon
  setups for isolating workload identity/permissions inside a cluster —
  node-level rootless mode matters most for standalone Docker/CI-runner
  use, not typical multi-tenant Kubernetes nodes.
- Track CRI-O's Kubernetes-version lock-step explicitly in upgrade
  planning; a CRI-O version mismatched with the target kubelet version
  is not a supported combination even if it appears to start.

## Common pitfalls

- **Symptom:** A node fails to join the cluster, or kubelet logs show
  cgroup-driver related errors, right after provisioning.
  **Fix:** The kubelet's `cgroupDriver` and the runtime's own cgroup
  driver setting (containerd's `SystemdCgroup` option, CRI-O's
  equivalent) disagree — align both to `systemd` (the current
  recommended default across distributions) and restart both services.

- **Symptom:** A pod requesting a sandboxed `RuntimeClass` (gVisor/Kata)
  gets stuck in `CreateContainerError` with a handler-not-found-style
  message.
  **Fix:** The `RuntimeClass` Kubernetes object was created, but the
  corresponding runtime handler was never installed/registered in the
  node's containerd `config.toml` (`runtimes.runsc`/`runtimes.kata`).
  Both the Kubernetes-level `RuntimeClass` and the node-level runtime
  installation are required; neither alone is sufficient.

- **Symptom:** After a Kubernetes upgrade past 1.23/1.24, a legacy node
  image referencing `docker://` as the container runtime fails to
  bootstrap entirely.
  **Fix:** dockershim was removed in-tree in Kubernetes 1.24 with no
  fallback — this is not a configuration bug to patch around. Reprovision
  the node with a containerd- or CRI-O-based image before attempting to
  join it to a 1.24+ control plane.

- **Symptom:** Private registry pulls fail on some nodes but not others
  despite identical Kubernetes-level `imagePullSecrets`.
  **Fix:** Node-level containerd registry auth config
  (`/etc/containerd/config.toml` or the newer `hosts.toml`-per-registry
  layout) drifted between nodes — confirm the auth config is applied
  identically across all nodes via bootstrap automation rather than a
  manual per-node edit, since `imagePullSecrets` and node-level
  containerd auth are two separate mechanisms that can each mask or
  duplicate the other depending on which the scheduler happens to hit.

- **Symptom:** `crictl` commands fail with a connection error even
  though `kubectl` shows the node `Ready` and pods running fine.
  **Fix:** `crictl` is pointed at the wrong CRI socket
  (`/etc/crictl.yaml` `runtime-endpoint`) — common after migrating a
  node from one runtime to another without updating this config file;
  point it explicitly at the active runtime's socket
  (`unix:///run/containerd/containerd.sock` for containerd,
  `unix:///var/run/crio/crio.sock` for CRI-O).

## Worked example

**Scenario:** Configure a containerd-based node to use `systemd`
cgroups, mirror Docker Hub through an internal cache, and add a gVisor
`RuntimeClass` for an untrusted-code-execution workload.

```toml
# /etc/containerd/config.toml
version = 2

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
  SystemdCgroup = true

[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
  endpoint = ["https://mirror.internal.example.com", "https://registry-1.docker.io"]

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runsc]
  runtime_type = "io.containerd.runsc.v1"
```

```bash
sudo systemctl restart containerd
sudo crictl info | grep -A2 cgroupDriver   # confirm systemd is active
```

```yaml
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata: { name: gvisor }
handler: runsc
---
apiVersion: v1
kind: Pod
metadata: { name: untrusted-job }
spec:
  runtimeClassName: gvisor
  containers:
    - name: sandboxed
      image: ghcr.io/example/untrusted-runner:2.1.0
```

```bash
kubectl apply -f gvisor-runtimeclass.yaml -f untrusted-pod.yaml
kubectl get pod untrusted-job
sudo crictl ps -a | grep untrusted-job
sudo crictl inspect <container-id> | grep -i runtimeType
```

The pod reaches `Running`, and `crictl inspect` confirms the container
was actually created under `io.containerd.runsc.v1` (gVisor) rather than
the default `runc`, giving the untrusted workload a syscall-interception
sandbox boundary in addition to standard Kubernetes RBAC/NetworkPolicy
isolation.

## Cross-references

- [lightweight-kubernetes-k3s](../lightweight-kubernetes-k3s/SKILL.md) — K3s bundles and manages containerd internally; the same cgroup-driver and registry-mirror concepts apply.
- [managed-kubernetes-eks-aks-gke](../managed-kubernetes-eks-aks-gke/SKILL.md) — node image/runtime choices and constraints on managed Kubernetes node groups/pools.
- [openshift-and-rosa-platform](../openshift-and-rosa-platform/SKILL.md) — CRI-O as OpenShift's default node runtime and its Kubernetes-version lock-step.
- [container-build-and-release](../../../devops/skills/container-build-and-release/SKILL.md) — building, tagging, and scanning the images this runtime executes (a separate concern from the runtime engine itself).

Wersje

W bazie nie ma innych skilli o nazwie container-runtime-docker-containerd.

Migawka bazy z 28.10.2026 · wersja paczki 14b59cf660eb (skrót SHA-256 całej paczki)

Zgłoś problem z tym skillem: szkodliwa treść, błędny opis albo prośba autora o usunięcie.

Podobne skille

  • 100runtimes
    Porównuje środowiska kontenerowe Docker, Podman i containerd i pomaga wybrać właściwe do konkretnego zastosowania.
  • 100docker
    Obejmuje Docker Engine we wszystkich wspieranych wersjach: architekturę dockerd, containerd i runc, BuildKit, optymalizację Dockerfile, Compose v2, sieci, sterowniki storage, utwardzanie bezpieczeństwa i Docker Scout.
  • 100podman
    Zarządza kontenerami w Podman: kontenery rootless, pody, obrazy i polecenia zgodne z Dockerem.
  • 100apple-container
    Obsługuje CLI container od Apple do budowania i uruchamiania kontenerów OCI jako lekkich maszyn wirtualnych na macOS z Apple Silicon, bez demona Docker.
  • 100sandbox
    Kieruje do właściwej metody izolowania agentów AI według systemu operacyjnego, poziomu izolacji i skali wdrożenia, porównując gVisor, Kata, Apple Container i Docker.

Uwagi i zgłoszenia

Wiadomość trafi do Bartosza Sokolińskiego. Adres e-mail jest potrzebny tylko do odpowiedzi. Szczegóły w polityce prywatności.