Skip to content

crictl rmi removes all images with the same image id instead of the specified tag #1911

@nirs

Description

@nirs

What happened:

Trying to debug minikube bug with removing images, turns out the minikube image rm uses crictl rmi image:tag under the hood.

So I have 3 images, created using:

$ sudo nerdctl -n k8s.io pull docker.io/kicbase/echo-server:1.0
docker.io/kicbase/echo-server:1.0:                                                resolved       |++++++++++++++++++++++++++++++++++++++| 
index-sha256:127ac38a2bb9537b7f252addff209ea6801edcac8a92c8b1104dacd66a583ed6:    done           |++++++++++++++++++++++++++++++++++++++| 
manifest-sha256:42a89d9b22e5307cb88494990d5d929c401339f508c0a7e98a4d8ac52623fc5b: done           |++++++++++++++++++++++++++++++++++++++| 
config-sha256:ce2d2cda2d858fdaea84129deb86d18e5dbf1c548f230b79fdca74cc91729d17:   done           |++++++++++++++++++++++++++++++++++++++| 
layer-sha256:ac2c07efdce850736ed8e7b9c3bc15e251d808fc43b9eeeb88797be0def23730:    done           |++++++++++++++++++++++++++++++++++++++| 
elapsed: 3.4 s                                                                    total:  2.4 Ki (725.0 B/s)                                       

$ sudo nerdctl -n k8s.io image tag docker.io/kicbase/echo-server:1.0 localhost/test-base:latest

$ sudo nerdctl -n k8s.io image tag localhost/test-base:latest localhost/test-tag:latest

$ sudo nerdctl -n k8s.io image ls | grep 127ac38a2bb9
localhost/test-tag                         latest                127ac38a2bb9    8 seconds ago     linux/arm64    4.792MB    1.976MB
localhost/test-base                        latest                127ac38a2bb9    19 seconds ago    linux/arm64    4.792MB    1.976MB
<none>                                     <none>                127ac38a2bb9    31 seconds ago    linux/arm64    4.792MB    1.976MB
kicbase/echo-server                        1.0                   127ac38a2bb9    31 seconds ago    linux/arm64    4.792MB    1.976MB

The purpose of the images is to test minikube image commands. For every test we want to create a new tag and preform an operation on the tag, like deleting it. The other images should bot be affected. This allows running tests in parallel since every test operates on its own image.

The unexpected hehavior - when deleting one tag, all the images with the same image id are deleted:

$ sudo crictl --debug rmi localhost/test-tag:latest
DEBU[0000] Get image connection                         
DEBU[0000] User specified image to be removed: localhost/test-tag:latest 
DEBU[0000] ImageStatusRequest: image:{image:"localhost/test-tag:latest"} 
DEBU[0000] ImageStatusResponse: image:{id:"sha256:ce2d2cda2d858fdaea84129deb86d18e5dbf1c548f230b79fdca74cc91729d17"  repo_tags:"docker.io/kicbase/echo-server:1.0"  repo_tags:"localhost/test-base:latest"  repo_tags:"localhost/test-tag:latest"  size:1977221} 
DEBU[0000] RemoveImageRequest: image:{image:"localhost/test-tag:latest"} 
Deleted: docker.io/kicbase/echo-server:1.0
Deleted: localhost/test-base:latest
Deleted: localhost/test-tag:latest

What you expected to happen:

Only the tag "localhost/test-tag:latest" is deleted.

This works as expected with both ctr image rm and nerdcl image rm.

ctr:

$ sudo ctr -n k8s.io image rm localhost/test-tag:latest
localhost/test-tag:latest

$ sudo ctr -n k8s.io image ls | grep 127ac38a2bb9537b7f252addff209ea6801edcac8a92c8b1104dacd66a583ed6
docker.io/kicbase/echo-server:1.0                                       application/vnd.docker.distribution.manifest.list.v2+json sha256:127ac38a2bb9537b7f252addff209ea6801edcac8a92c8b1104dacd66a583ed6 1.9 MiB   linux/amd64,linux/arm64                                                      io.cri-containerd.image=managed                                 
localhost/test-base:latest                                              application/vnd.docker.distribution.manifest.list.v2+json sha256:127ac38a2bb9537b7f252addff209ea6801edcac8a92c8b1104dacd66a583ed6 1.9 MiB   linux/amd64,linux/arm64                                                      io.cri-containerd.image=managed                                 
sha256:ce2d2cda2d858fdaea84129deb86d18e5dbf1c548f230b79fdca74cc91729d17 application/vnd.docker.distribution.manifest.list.v2+json sha256:127ac38a2bb9537b7f252addff209ea6801edcac8a92c8b1104dacd66a583ed6 1.9 MiB   linux/amd64,linux/arm64                                                      io.cri-containerd.image=managed                                 

nerdctl:

$ sudo nerdctl -n k8s.io image rm localhost/test-tag:latest
Untagged: localhost/test-tag:latest@sha256:127ac38a2bb9537b7f252addff209ea6801edcac8a92c8b1104dacd66a583ed6
Deleted: sha256:5d26d12357a043b2446bf19e036f55cee8454728871f8dbe007f3127cd22d649

$ sudo nerdctl -n k8s.io image ls | grep 127ac38a2bb9
localhost/test-base                        latest                127ac38a2bb9    4 minutes ago    linux/arm64    4.792MB    1.976MB
<none>                                     <none>                127ac38a2bb9    4 minutes ago    linux/arm64    4.792MB    1.976MB
kicbase/echo-server                        1.0                   127ac38a2bb9    4 minutes ago    linux/arm64    4.792MB    1.976MB

How to reproduce it (as minimally and precisely as possible):

As explained above. Reproducible with both

Anything else we need to know?:

Environment:

  • Container runtime or hardware configuration:

With containerd 2.1.4:

$ sudo crictl --version
crictl version v1.34.0

$ sudo crictl info     
{
  "cniconfig": {
    "Networks": [
      {
        "Config": {
          "CNIVersion": "0.3.1",
          "Name": "cni-loopback",
          "Plugins": [
            {
              "Network": {
                "ipam": {},
                "type": "loopback"
              },
              "Source": "{\"type\":\"loopback\"}"
            }
          ],
          "Source": "{\n\"cniVersion\": \"0.3.1\",\n\"name\": \"cni-loopback\",\n\"plugins\": [{\n  \"type\": \"loopback\"\n}]\n}"
        },
        "IFName": "lo"
      },
      {
        "Config": {
          "CNIVersion": "0.4.0",
          "Name": "bridge",
          "Plugins": [
            {
              "Network": {
                "ipam": {
                  "type": "host-local"
                },
                "type": "bridge"
              },
              "Source": "{\"addIf\":\"true\",\"bridge\":\"bridge\",\"forceAddress\":false,\"hairpinMode\":true,\"ipMasq\":true,\"ipam\":{\"subnet\":\"10.244.0.0/16\",\"type\":\"host-local\"},\"isDefaultGateway\":true,\"type\":\"bridge\"}"
            },
            {
              "Network": {
                "capabilities": {
                  "portMappings": true
                },
                "ipam": {},
                "type": "portmap"
              },
              "Source": "{\"capabilities\":{\"portMappings\":true},\"type\":\"portmap\"}"
            },
            {
              "Network": {
                "ipam": {},
                "type": "firewall"
              },
              "Source": "{\"type\":\"firewall\"}"
            }
          ],
          "Source": "\n{\n  \"cniVersion\": \"0.4.0\",\n  \"name\": \"bridge\",\n  \"plugins\": [\n    {\n      \"type\": \"bridge\",\n      \"bridge\": \"bridge\",\n      \"addIf\": \"true\",\n      \"isDefaultGateway\": true,\n      \"forceAddress\": false,\n      \"ipMasq\": true,\n      \"hairpinMode\": true,\n      \"ipam\": {\n          \"type\": \"host-local\",\n          \"subnet\": \"10.244.0.0/16\"\n      }\n    },\n    {\n      \"type\": \"portmap\",\n      \"capabilities\": {\n          \"portMappings\": true\n      }\n    },\n    {\n       \"type\": \"firewall\"\n    }\n  ]\n}\n"
        },
        "IFName": "eth0"
      }
    ],
    "PluginConfDir": "/etc/cni/net.d",
    "PluginDirs": [
      "/opt/cni/bin"
    ],
    "PluginMaxConfNum": 1,
    "Prefix": "eth"
  },
  "config": {
    "cdiSpecDirs": [
      "/etc/cdi",
      "/var/run/cdi"
    ],
    "cni": {
      "binDir": "",
      "binDirs": [
        "/opt/cni/bin"
      ],
      "confDir": "/etc/cni/net.d",
      "confTemplate": "",
      "ipPref": "",
      "maxConfNum": 1,
      "setupSerially": false,
      "useInternalLoopback": false
    },
    "containerd": {
      "defaultRuntimeName": "runc",
      "ignoreBlockIONotEnabledErrors": false,
      "ignoreRdtNotEnabledErrors": false,
      "runtimes": {
        "runc": {
          "ContainerAnnotations": null,
          "PodAnnotations": null,
          "baseRuntimeSpec": "",
          "cgroupWritable": false,
          "cniConfDir": "",
          "cniMaxConfNum": 0,
          "io_type": "",
          "options": {
            "BinaryName": "",
            "CriuImagePath": "",
            "CriuWorkPath": "",
            "IoGid": 0,
            "IoUid": 0,
            "NoNewKeyring": false,
            "Root": "",
            "ShimCgroup": "",
            "SystemdCgroup": false
          },
          "privileged_without_host_devices": false,
          "privileged_without_host_devices_all_devices_allowed": false,
          "runtimePath": "",
          "runtimeType": "io.containerd.runc.v2",
          "sandboxer": "podsandbox",
          "snapshotter": ""
        }
      }
    },
    "containerdEndpoint": "/run/containerd/containerd.sock",
    "containerdRootDir": "/mnt/vdb1/var/lib/containerd",
    "device_ownership_from_security_context": false,
    "disableApparmor": false,
    "disableHugetlbController": true,
    "disableProcMount": false,
    "drainExecSyncIOTimeout": "0s",
    "enableCDI": true,
    "enableSelinux": false,
    "enableUnprivilegedICMP": true,
    "enableUnprivilegedPorts": true,
    "ignoreDeprecationWarnings": null,
    "ignoreImageDefinedVolumes": false,
    "maxContainerLogLineSize": 16384,
    "netnsMountsUnderStateDir": false,
    "restrictOOMScoreAdj": false,
    "rootDir": "/mnt/vdb1/var/lib/containerd/io.containerd.grpc.v1.cri",
    "selinuxCategoryRange": 1024,
    "stateDir": "/run/containerd/io.containerd.grpc.v1.cri",
    "tolerateMissingHugetlbController": true,
    "unsetSeccompProfile": ""
  },
  "features": {
    "supplemental_groups_policy": true
  },
  "golang": "go1.23.11",
  "lastCNILoadStatus": "OK",
  "lastCNILoadStatus.default": "OK",
  "runtimeHandlers": [
    {
      "features": {
        "recursive_read_only_mounts": true,
        "user_namespaces": true
      }
    },
    {
      "features": {
        "recursive_read_only_mounts": true,
        "user_namespaces": true
      },
      "name": "runc"
    }
  ],
  "status": {
    "conditions": [
      {
        "message": "",
        "reason": "",
        "status": true,
        "type": "RuntimeReady"
      },
      {
        "message": "",
        "reason": "",
        "status": true,
        "type": "NetworkReady"
      },
      {
        "message": "",
        "reason": "",
        "status": true,
        "type": "ContainerdHasNoDeprecationWarnings"
      }
    ]
  }
}
  • OS (e.g: cat /etc/os-release):
$ cat /etc/os-release 
NAME=Buildroot
VERSION=2025.02-dirty
ID=buildroot
VERSION_ID=2025.02
PRETTY_NAME="Buildroot 2025.02"
  • Kernel (e.g. uname -a):
$ uname -a
Linux minikube 6.6.95 #1 SMP PREEMPT Tue Sep  2 22:29:31 UTC 2025 aarch64 GNU/Linux
  • Others:

Note: the minikube image mention comes with crictl 1.28.0. I installed crictl 1.34.0 manually to check if the issue is related to the old version. The behavior is the same.

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/bugCategorizes issue or PR as related to a bug.sig/nodeCategorizes an issue or PR as relevant to SIG Node.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions