Container(Runtime)
π¦ Container(Runtime) β the CLI page, bestie edition π¦
okay so. you opened the Container(Runtime) manual, CLI section, and honestly? iconic choice. grab a boba, we're doing this together. π
crictl provides a CLI for CRI-compatible container runtimes. that's the whole vibe. it lets the CRI runtime developers debug their runtime without needing to set up Kubernetes components β no cluster, no yaml mountain, just you and your runtime, one-on-one. π«Ά
crictlhas been GA since v1.11.0 and is currently under active development. it is hosted at the cri-tools repositoryhttps://github.com/kubernetes-sigs/cri-tools. we encourage the CRI developers to report bugs or help extend the coverage by adding more functionalities. so like, pls contribute, i'm begging. π- the tool expects JSON or YAML encoded files as input and passes them to the corresponding container runtime using the CRI API protocol
/vendor/k8s.io/cri-api/pkg/apis/runtime/v1/api.proto. yes the path is that long. no i will not be shortening it.
πΈ Install crictl πΈ
NOTE: the below steps are based on linux-amd64, however you can get downloads for all other platforms (Windows, ARM, etc) in the releases page https://github.com/kubernetes-sigs/cri-tools/releases.
crictl can be downloaded from the cri-tools release page https://github.com/kubernetes-sigs/cri-tools/releases:
- using
wget:
VERSION="v1.36.0"
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-$VERSION-linux-amd64.tar.gz
sudo tar zxvf crictl-$VERSION-linux-amd64.tar.gz -C /usr/local/bin
rm -f crictl-$VERSION-linux-amd64.tar.gz
- using
curl:
VERSION="v1.36.0"
curl -L https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-${VERSION}-linux-amd64.tar.gz --output crictl-${VERSION}-linux-amd64.tar.gz
sudo tar zxvf crictl-$VERSION-linux-amd64.tar.gz -C /usr/local/bin
rm -f crictl-$VERSION-linux-amd64.tar.gz
β¨ Usage β¨
the shape of every command you'll ever run:
crictl [global options] command [command options] [arguments...]
COMMANDS:
attachβ Attach to a running containercreateβ Create a new containerexecβ Run a command in a running containerversionβ Display runtime version informationimages,image,imgβ List imagesinspectβ Display the status of one or more containersinspectiβ Return the status of one or more imagesimagefsinfoβ Return image filesystem infoinspectpβ Display the status of one or more podslogsβ Fetch the logs of a containermetricspβ List pod metrics. Metrics are unstructured key/value pairs gathered by CRI meant to replace cAdvisor's/metrics/cadvisorendpoint.metricdescsβ List metric descriptors. Returns information about the metrics available through the CRI.port-forwardβ Forward local port to a podpsβ List containerspullβ Pull an image from a registryrunβ Run a new container inside a sandboxrunpβ Run a new podrmβ Remove one or more containersrmiβ Remove one or more imagesrmpβ Remove one or more podspodsβ List podsstartβ Start one or more created containersinfoβ Display information of the container runtimestopβ Stop one or more running containersstoppβ Stop one or more running podsupdateβ Update one or more running containersconfigβ Get, set and list crictl configuration optionsstatsβ List container(s) resource usage statisticsstatspβ List pod statistics. Stats represent a structured API that will fulfill the Kubelet's/stats/summaryendpoint.completionβ Output bash shell completion codecheckpointβ Checkpoint one or more running containersevents,eventβ Stream the events of containersruntime-configβ Retrieve the container runtime configurationupdate-runtime-configβ Update the runtime configurationhelp,hβ Shows a list of commands or help for one command
that's a lot of commands and every single one of them ate. π
crictl by default connects on Unix to:
unix:///run/containerd/containerd.sockorunix:///run/crio/crio.sockorunix:///var/run/cri-dockerd.sock
or on Windows to:
npipe:////./pipe/containerd-containerdornpipe:////./pipe/cri-dockerd
The endpoint can be set in three ways:
- By setting global option flags
--runtime-endpoint(-r) and--image-endpoint(-i) - By setting environment variables
CONTAINER_RUNTIME_ENDPOINTandIMAGE_SERVICE_ENDPOINT - By setting the endpoint in the config file
--config=/etc/crictl.yaml
If the endpoint is not set then it works as follows:
- If the runtime endpoint is not set,
crictlwill by default try to connect using:- containerd
- cri-o
- cri-dockerd
- If the image endpoint is not set,
crictlwill by default use the runtime endpoint setting
Note: the default endpoints are now deprecated and the runtime endpoint should always be set instead. The performance maybe affected as each default connection attempt takes n-seconds to complete before timing out and going to the next in sequence. like, it's gonna sit there tapping its foot waiting. just set the endpoint, bestie. π
Unix:
$ cat /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 2
debug: true
pull-image-on-create: false
max-retries: 3
Windows:
C:\> type %USERPROFILE%\.crictl\crictl.yaml
runtime-endpoint: npipe:////./pipe/containerd-containerd
image-endpoint: npipe:////./pipe/containerd-containerd
timeout: 2
debug: true
pull-image-on-create: false
max-retries: 3
π₯ Connection troubleshooting π₯
some runtimes might use cmux https://github.com/soheilhy/cmux for connection multiplexing, which can cause issues during the initial gRPC https://grpc.io connection setup. so if it does not seem to be possible to connect to the runtime *.sock, then exporting the environment variable GRPC_GO_REQUIRE_HANDSHAKE=off might solve the issue. π‘
pls take into account that the environment has to be preserved when running viasudoβ that meanssudo -E crictl ..., okay? don't forget the-Eor the env vanishes and you'll be sad. π«
π Additional options π
--timeout,-tβ Timeout of connecting to server in seconds (default:2s).0or less is interpreted as unset and converted to the default. There is no option for no timeout value set and the smallest supported timeout is1s. so like,1sis the floor, periodt.--debug,-Dβ Enable debug output--help,-hβ show help--version,-vβ print the version information ofcrictl--config,-cβ Location of the client config file (default:/etc/crictl.yaml). Can be changed by settingCRI_CONFIG_FILEenvironment variable. If not specified and the default does not exist, the program's directory is searched as well--enable-tracingβ Enable OpenTelemetry tracing (default:false)--tracing-endpointβ Address to which the gRPC tracing collector will send spans to (default:127.0.0.1:4317)--tracing-sampling-rate-per-millionβ Number of samples to collect per million OpenTelemetry spans. Set to1000000or-1to always sample (default:-1)--max-retriesβ Max retries for connecting to an explicitly set endpoint with exponential backoff (default:3,0to disable, negative for infinite)--profile-cpuβ Write a pprof CPU profile to the provided path--profile-memβ Write a pprof memory profile to the provided path
π Client Configuration Options π
use the crictl config command to get, set and list the crictl client configuration options. it's giving control panel. β¨
USAGE:
crictl config [command options] [<crictl options>]
for example crictl config --set debug=true will enable debug mode when giving subsequent crictl commands. so you set it once and every command after that is in debug mode. slay.
COMMAND OPTIONS:
--getvalue β Show the option value--setvalue β Set option (can specify multiple or separate values with commas:opt1=val1,opt2=val2)--listβ Show all option values (default:false)--help,-hβ Show help (default:false)
crictl OPTIONS:
runtime-endpointβ Container runtime endpoint (no default value)image-endpointβ Image endpoint (no default value)timeoutβ Timeout of connecting to server (default:2s)debugβ Enable debug output (default:false)pull-image-on-createβ Enable pulling image on create requests (default:false)disable-pull-on-runβ Disable pulling image on run requests (default:false)max-retriesβ Max retries for connecting to an explicitly set endpoint (default:3,0to disable, negative for infinite)
When enabledpull-image-on-createmodifies the create container command to first pull the container's image. This feature is used as a helper to make creating containers easier and faster. Some users ofcrictlmay desire to not pull the image necessary to create the container. For example, the image may have already been pulled or otherwise loaded into the container runtime, or the user may be running without a network. For this reason the default forpull-image-on-createisfalse.
By default theruncommand first pulls the container image, anddisable-pull-on-runisfalse. Some users ofcrictlmay desire to setdisable-pull-on-runtotrueto not pull the image by default when using theruncommand.
To override these default pull configuration settings,--no-pulland--with-pulloptions are provided for thecreateandruncommands.
β Examples β
- Run pod sandbox with config file
- Run pod sandbox with runtime handler
- Pull a busybox image
- Filter images
π Run pod sandbox with config file π
$ cat pod-config.json
{
"metadata": {
"name": "nginx-sandbox",
"namespace": "default",
"attempt": 1,
"uid": "hdishd83djaidwnduwk28bcsb"
},
"log_directory": "/tmp",
"linux": {
}
}
if the runtime uses systemd as the cgroup driver, set the "cgroup_parent" field in the pod-config, similar to:
$ cat pod-config.json
{
"metadata": {
"name": "nginx-sandbox",
"namespace": "default",
"attempt": 1,
"uid": "hdishd83djaidwnduwk28bcsb"
},
"log_directory": "/tmp",
"linux": {
"cgroup_parent": "/test.slice"
}
}
$ crictl runp pod-config.json
f84dd361f8dc51518ed291fbadd6db537b0496536c1d2d6c05ff943ce8c9a54f
then list pod sandboxes and check the sandbox is in Ready state:
$ crictl pods
POD ID CREATED STATE NAME NAMESPACE ATTEMPT
f84dd361f8dc5 17 seconds ago Ready nginx-sandbox default 1
look at that Ready. she's ready, bestie. π
π§ Run pod sandbox with runtime handler π§
runtime handler requires runtime support. the following example shows running a pod sandbox with runsc handler on containerd runtime.
$ cat pod-config.json
{
"metadata": {
"name": "nginx-runsc-sandbox",
"namespace": "default",
"attempt": 1,
"uid": "hdishd83djaidwnduwk28bcsb"
},
"log_directory": "/tmp",
"linux": {
}
}
$ crictl runp --runtime=runsc pod-config.json
c112976cb6caa43a967293e2c62a2e0d9d8191d5109afef230f403411147548c
$ crictl inspectp c112976cb6caa43a967293e2c62a2e0d9d8191d5109afef230f403411147548c
...
"runtime": {
"runtimeType": "io.containerd.runtime.v1.linux",
"runtimeEngine": "/usr/local/sbin/runsc",
"runtimeRoot": "/run/containerd/runsc"
},
...
ok so the sandbox is up, and when you peek inside it with inspectp the runtime deets are sitting right there in the output (runtimeType, runtimeEngine, runtimeRoot β the whole squad). iconic. π
π³ Pull a busybox image
bestie we need an image, so let's go get one:
$ crictl pull busybox
Image is up to date for busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47
now list your images and vibe check that busybox actually showed up:
$ crictl images
IMAGE TAG IMAGE ID SIZE
busybox latest 8c811b4aec35f 1.15MB
k8s.gcr.io/pause 3.1 da86e6ba6ca19 742kB
there it is, busybox latest, sitting pretty. 1.15MB of pure potential. π¦
ποΈ Remove images
the crictl rmi command removes one or more images by ID or reference. simple. except... it is NOT that simple, and this is the part where you sit down.
Important Note: Due to CRI API limitations, when you specify an image by tag (e.g.,localhost/test:latest), the entire image will be removed along with all of its tags, not just the specified tag. This behavior differs fromdocker rmi,nerdctl rmi, andctr image rm, which only remove the specified tag.
fr fr, that's the whole image gone. every tag. poof. π
so if you need to remove only a specific tag while keeping the image and other tags, use the container runtime's native CLI tool instead:
- For containerd:
nerdctl image rm <tag>orctr image rm <tag> - For CRI-O, use Podman:
podman rmi <tag> - For Docker:
docker rmi <tag>
and here's an example showing the difference, because seeing it hurts different:
# Image with multiple tags
$ crictl images
IMAGE TAG IMAGE ID SIZE
localhost/test latest abc123def456 10MB
localhost/test v1.0 abc123def456 10MB
localhost/base latest abc123def456 10MB
# Running crictl rmi will remove ALL tags
$ crictl rmi localhost/test:latest
WARN[0000] Image "localhost/test:latest" has multiple tags. Removing this image will delete all of the following tags:
WARN[0000] localhost/test:latest
WARN[0000] localhost/test:v1.0
WARN[0000] localhost/base:latest
Deleted: localhost/test:latest
Deleted: localhost/test:v1.0
Deleted: localhost/base:latest
# All tags are now gone
$ crictl images
IMAGE TAG IMAGE ID SIZE
see?? you asked for one tag, you got a whole funeral. π the warnings are your last chance to back out β read them.
π Filter images
you can filter your image list with --filter, -f, and these are the filters on the menu:
before=<image-name>[:<tag>]|<image id>|<image@digest>dangling=(true/false)reference=/regex/since=<image-name>[:<tag>]|<image id>|<image@digest>
filters can be combined, and they get applied in the order you provided them. stack 'em, bestie. π
list all images:
$ crictl images --digests
IMAGE TAG DIGEST IMAGE ID SIZE
docker.io/library/busybox latest 538721340ded1 3f57d9401f8d4 4.5MB
docker.io/library/nginx latest 05aa73005987c e4720093a3c13 191MB
gcr.io/k8s-staging-cri-tools/hostnet-nginx-amd64 latest aa74ea387dbbe 1ee3f9825c42b 147MB
gcr.io/k8s-staging-cri-tools/test-image-predefined-group latest 2b2fc189c502a 84410ab6e30d9 5.11MB
registry.k8s.io/e2e-test-images/busybox 1.29-2 c318242786b13 84eebb9ca1734 1.37MB
registry.k8s.io/e2e-test-images/httpd 2.4.39-4 3fe7acf013d12 444b9e2765dc9 132MB
registry.k8s.io/e2e-test-images/nginx 1.14-2 13616070e3f29 02e45a31af51c 17.2MB
registry.k8s.io/e2e-test-images/nonewprivs 1.3 8ac1264691820 3e3d1785c0b6e 7.37MB
registry.k8s.io/pause 3.9 7031c1b283388 e6f1816883972 750kB
list images by reference:
$ crictl images --filter 'reference=k8s'
IMAGE TAG IMAGE ID SIZE
gcr.io/k8s-staging-cri-tools/hostnet-nginx-amd64 latest 1ee3f9825c42b 147MB
gcr.io/k8s-staging-cri-tools/test-image-predefined-group latest 84410ab6e30d9 5.11MB
registry.k8s.io/e2e-test-images/busybox 1.29-2 84eebb9ca1734 1.37MB
registry.k8s.io/e2e-test-images/httpd 2.4.39-4 444b9e2765dc9 132MB
registry.k8s.io/e2e-test-images/nginx 1.14-2 02e45a31af51c 17.2MB
registry.k8s.io/e2e-test-images/nonewprivs 1.3 3e3d1785c0b6e 7.37MB
registry.k8s.io/pause 3.9 e6f1816883972 750kB
list images by reference using a regular expression:
$ crictl images --filter 'reference=nginx'
IMAGE TAG IMAGE ID SIZE
docker.io/library/nginx latest e4720093a3c13 191MB
gcr.io/k8s-staging-cri-tools/hostnet-nginx-amd64 latest 1ee3f9825c42b 147MB
registry.k8s.io/e2e-test-images/nginx 1.14-2 02e45a31af51c 17.2MB
$ crictl images --filter 'reference=.*(nginx)$'
IMAGE TAG IMAGE ID SIZE
docker.io/library/nginx latest e4720093a3c13 191MB
registry.k8s.io/e2e-test-images/nginx 1.14-2 02e45a31af51c 17.2MB
combine multiple --filter arguments together, because one filter is never enough:
$ crictl images --filter 'reference=nginx' --filter 'reference=\.k8s\.'
IMAGE TAG IMAGE ID SIZE
registry.k8s.io/e2e-test-images/nginx 1.14-2 02e45a31af51c 17.2MB
$ crictl images --filter 'since=registry.k8s.io/e2e-test-images/busybox@sha256:c318242786b139d18676b1c09a0ad7f15fc17f8f16a5b2e625cd0dc8c9703daf' --filter 'reference=nginx'
IMAGE TAG IMAGE ID SIZE
docker.io/library/nginx latest e4720093a3c13 191MB
gcr.io/k8s-staging-cri-tools/hostnet-nginx-amd64 latest 1ee3f9825c42b 147MB
list images before=<image-name>[:<tag>]:
$ crictl images --filter 'before=gcr.io/k8s-staging-cri-tools/hostnet-nginx-amd64:latest'
IMAGE TAG IMAGE ID SIZE
gcr.io/k8s-staging-cri-tools/test-image-predefined-group latest 84410ab6e30d9 5.11MB
registry.k8s.io/e2e-test-images/busybox 1.29-2 84eebb9ca1734 1.37MB
registry.k8s.io/e2e-test-images/httpd 2.4.39-4 444b9e2765dc9 132MB
registry.k8s.io/e2e-test-images/nginx 1.14-2 02e45a31af51c 17.2MB
registry.k8s.io/e2e-test-images/nonewprivs 1.3 3e3d1785c0b6e 7.37MB
registry.k8s.io/pause 3.9 e6f1816883972 750kB
list images since=<image-name>[:<tag>]:
$ crictl images --filter 'since=gcr.io/k8s-staging-cri-tools/hostnet-nginx-amd64:latest'
IMAGE TAG IMAGE ID SIZE
docker.io/library/busybox latest 3f57d9401f8d4 4.5MB
docker.io/library/nginx latest e4720093a3c13 191MB
list images since=<image@digest>:
crictl images --filter 'since=registry.k8s.io/e2e-test-images/busybox@sha256:c318242786b139d18676b1c09a0ad7f15fc17f8f16a5b2e625cd0dc8c9703daf'
IMAGE TAG IMAGE ID SIZE
docker.io/library/busybox latest 3f57d9401f8d4 4.5MB
docker.io/library/nginx latest e4720093a3c13 191MB
gcr.io/k8s-staging-cri-tools/hostnet-nginx-amd64 latest 1ee3f9825c42b 147MB
gcr.io/k8s-staging-cri-tools/test-image-predefined-group latest 84410ab6e30d9 5.11MB
π¦ Create container in the pod sandbox with config file
two config files, one container, let's go. β¨
$ cat pod-config.json
{
"metadata": {
"name": "nginx-sandbox",
"namespace": "default",
"attempt": 1,
"uid": "hdishd83djaidwnduwk28bcsb"
},
"log_directory": "/tmp",
"linux": {
}
}
$ cat container-config.json
{
"metadata": {
"name": "busybox"
},
"image":{
"image": "busybox"
},
"command": [
"top"
],
"log_path":"busybox.0.log",
"linux": {
}
}
$ crictl create f84dd361f8dc51518ed291fbadd6db537b0496536c1d2d6c05ff943ce8c9a54f container-config.json pod-config.json
3e025dd50a72d956c4f14881fbb5b1080c9275674e95fb67f965f6478a957d60
now list the containers and check that ours is in Created state (yes, -a shows you everything, not just the running ones):
$ crictl ps -a
CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT
3e025dd50a72d busybox 32 seconds ago Created busybox 0
Created, not running yet. it's waiting for you. π₯Ί
βΆοΈ Start container
do the thing:
$ crictl start 3e025dd50a72d956c4f14881fbb5b1080c9275674e95fb67f965f6478a957d60
3e025dd50a72d956c4f14881fbb5b1080c9275674e95fb67f965f6478a957d60
and now ps (no -a, because it's alive and it knows it):
$ crictl ps
CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT
3e025dd50a72d busybox About a minute ago Running busybox 0
Running. main character energy achieved. π
πΉοΈ Exec a command in container
jump inside and poke around:
crictl exec -i -t 3e025dd50a72d956c4f14881fbb5b1080c9275674e95fb67f965f6478a957d60 ls
bin dev etc home proc root sys tmp usr var
-i keeps stdin open, -t gives you a tty, and then it's just... ls. living in the container now. π§
β‘ Create and start a container within one command
plot twist: you don't even need two commands. it is possible to start a container within a single command, and the image will be pulled automatically too. one command, whole container, no cap π₯
$ cat pod-config.json
{
"metadata": {
"name": "nginx-sandbox",
"namespace": "default",
"attempt": 1,
"uid": "hdishd83djaidwnduwk28bcsb"
},
"log_directory": "/tmp",
"linux": {
}
}
Okay so bestie, that config file? Here's what it actually looks like when you write it out. It's giving β¨structuredβ¨:
$ cat container-config.json
{
"metadata": {
"name": "busybox"
},
"image":{
"image": "busybox"
},
"command": [
"top"
],
"log_path":"busybox.0.log",
"linux": {
}
}
And then you just... run it. Pass it your container config and your pod config, and it hands you back a container ID. That long hex string is literally the whole point β it's your new baby's name πΌ:
$ crictl run container-config.json pod-config.json
b25b4f26e342969eb40d05e98130eee0846557d667e93deac992471a3b8f1cf4
Now list containers and check the container is in Running state β like, vibe check your container, is it alive, is it thriving π :
$ crictl ps
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID
b25b4f26e3429 busybox:latest 14 seconds ago Running busybox 0 158d7a6665ff3
See that Running? That's the green flag. π’ We love to see it.
πΎ Checkpoint a running container
Okay this one is lowkey iconic. You can snapshot a running container's whole situation into a tarball with --export:
$ crictl checkpoint --export=/path/to/checkpoint.tar 39fcdd7a4f1d4
39fcdd7a4f1d4
$ ls /path/to/checkpoint.tar
/path/to/checkpoint.tar
The command echoes the container ID back at you (that's 39fcdd7a4f1d4, same energy as when you say someone's name and they go "yes? π₯Ί"), and boom β the tar file is sitting right there at /path/to/checkpoint.tar where you asked for it. Manifesting that checkpoint into existence. β¨
π More information
- π See the Kubernetes.io Debugging Kubernetes nodes with crictl doc β
https://kubernetes.io/docs/tasks/debug-application-cluster/crictl/ - π Visit kubernetes-sigs/cri-tools β
https://github.com/kubernetes-sigs/cri-toolsβ for more information.
And that's the whole page, bestie, we did it π«Ά This one's filed under the CRI section of the manual, Interface subsection, page name Container(Runtime) β that's the source/version tag, and it's dated as shown on the page itself. Go forth and debug your runtime without ever setting up Kubernetes components. Slay. ππ
π¦ where this page comes from
- fedora 43: cri-tools1.37 1.37.0-1.fc43 Β· Apache-2.0 AND BSD-2-Clause AND BSD-3-Clause AND ISC AND MIT AND MPL-2.0
- fedora 44: cri-tools1.37 1.37.0-1.fc44 Β· Apache-2.0 AND BSD-2-Clause AND BSD-3-Clause AND ISC AND MIT AND MPL-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms