Skip to content

Commit fc85e2f

Browse files
authored
Merge pull request #1974 from saschagrunert/fix-1911-rmi-multi-tag-warning
Add warning and documentation for crictl rmi multi-tag behavior
2 parents 5c37390 + be5cd06 commit fc85e2f

File tree

3 files changed

+110
-3
lines changed

3 files changed

+110
-3
lines changed

cmd/crictl/image.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -390,9 +390,16 @@ func outputImageStatusTable(r *pb.ImageStatusResponse, verbose bool) {
390390
}
391391

392392
var removeImageCommand = &cli.Command{
393-
Name: "rmi",
394-
Usage: "Remove one or more images",
395-
ArgsUsage: "IMAGE-ID [IMAGE-ID...]",
393+
Name: "rmi",
394+
Usage: "Remove one or more images",
395+
ArgsUsage: "IMAGE-ID [IMAGE-ID...]",
396+
Description: `Remove one or more images by ID or reference.
397+
398+
NOTE: Due to CRI API limitations, when you specify an image by tag (e.g., 'localhost/test:latest'),
399+
the entire image will be removed along with ALL of its tags, not just the specified tag.
400+
This behavior differs from 'docker rmi', 'nerdctl rmi', and 'ctr image rm', which only remove
401+
the specified tag. To remove only a specific tag, use the container runtime's native CLI tool
402+
(e.g., 'nerdctl', 'ctr', or 'podman').`,
396403
UseShortOptionHandling: true,
397404
Flags: []cli.Flag{
398405
&cli.BoolFlag{
@@ -496,6 +503,20 @@ var removeImageCommand = &cli.Command{
496503
return fmt.Errorf("no such image %s", id)
497504
}
498505

506+
// Warn if the user specified a tag and multiple tags would be removed
507+
repoTags := status.GetImage().GetRepoTags()
508+
if len(repoTags) > 1 {
509+
// Check if user specified a tag (contains ':' but doesn't start with 'sha256:')
510+
// or a repo name (contains '/' or is a name like 'localhost')
511+
isLikelyTag := !strings.HasPrefix(id, "sha256:") && (strings.Contains(id, ":") || strings.Contains(id, "/"))
512+
if isLikelyTag {
513+
logrus.Warnf("Image %q has multiple tags. Removing this image will delete all of the following tags:", id)
514+
for _, tag := range repoTags {
515+
logrus.Warnf(" %s", tag)
516+
}
517+
}
518+
}
519+
499520
if err := RemoveImage(cliCtx.Context, imageClient, id); err != nil {
500521
// We ignore further errors on prune because there might be
501522
// races

docs/crictl.1

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,51 @@ busybox latest 8c811b4aec35f 1.15MB
401401
k8s.gcr.io/pause 3.1 da86e6ba6ca19 742kB
402402
.EE
403403

404+
.SS Remove images
405+
The \fBcrictl rmi\fR command removes one or more images by ID or reference:
406+
407+
.EX
408+
$ crictl rmi busybox:latest
409+
.EE
410+
411+
.PP
412+
\fBImportant Note\fP: Due to CRI API limitations, when you specify an image by tag (e.g., \fBlocalhost/test:latest\fR), the entire image will be removed along with \fBall\fP of its tags, not just the specified tag. This behavior differs from \fBdocker rmi\fR, \fBnerdctl rmi\fR, and \fBctr image rm\fR, which only remove the specified tag.
413+
414+
.PP
415+
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:
416+
.IP \(bu 2
417+
For containerd: \fBnerdctl image rm <tag>\fR or \fBctr image rm <tag>\fR
418+
.IP \(bu 2
419+
For CRI-O, use Podman: \fBpodman rmi <tag>\fR
420+
.IP \(bu 2
421+
For Docker: \fBdocker rmi <tag>\fR
422+
423+
.PP
424+
Example showing the difference:
425+
426+
.EX
427+
# Image with multiple tags
428+
$ crictl images
429+
IMAGE TAG IMAGE ID SIZE
430+
localhost/test latest abc123def456 10MB
431+
localhost/test v1.0 abc123def456 10MB
432+
localhost/base latest abc123def456 10MB
433+
434+
# Running crictl rmi will remove ALL tags
435+
$ crictl rmi localhost/test:latest
436+
WARN[0000] Image "localhost/test:latest" has multiple tags. Removing this image will delete all of the following tags:
437+
WARN[0000] localhost/test:latest
438+
WARN[0000] localhost/test:v1.0
439+
WARN[0000] localhost/base:latest
440+
Deleted: localhost/test:latest
441+
Deleted: localhost/test:v1.0
442+
Deleted: localhost/base:latest
443+
444+
# All tags are now gone
445+
$ crictl images
446+
IMAGE TAG IMAGE ID SIZE
447+
.EE
448+
404449
.SS Filter images
405450
The following filters are available \fB--filter\fR, \fB-f\fR:
406451
.IP " 1." 5

docs/crictl.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,47 @@ busybox latest 8c811b4aec35f 1.15MB
293293
k8s.gcr.io/pause 3.1 da86e6ba6ca19 742kB
294294
```
295295

296+
### Remove images
297+
298+
The `crictl rmi` command removes one or more images by ID or reference:
299+
300+
```sh
301+
$ crictl rmi busybox:latest
302+
```
303+
304+
**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 from `docker rmi`, `nerdctl rmi`, and `ctr image rm`, which only remove the specified tag.
305+
306+
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:
307+
308+
- For containerd: `nerdctl image rm <tag>` or `ctr image rm <tag>`
309+
- For CRI-O, use Podman: `podman rmi <tag>`
310+
- For Docker: `docker rmi <tag>`
311+
312+
Example showing the difference:
313+
314+
```sh
315+
# Image with multiple tags
316+
$ crictl images
317+
IMAGE TAG IMAGE ID SIZE
318+
localhost/test latest abc123def456 10MB
319+
localhost/test v1.0 abc123def456 10MB
320+
localhost/base latest abc123def456 10MB
321+
322+
# Running crictl rmi will remove ALL tags
323+
$ crictl rmi localhost/test:latest
324+
WARN[0000] Image "localhost/test:latest" has multiple tags. Removing this image will delete all of the following tags:
325+
WARN[0000] localhost/test:latest
326+
WARN[0000] localhost/test:v1.0
327+
WARN[0000] localhost/base:latest
328+
Deleted: localhost/test:latest
329+
Deleted: localhost/test:v1.0
330+
Deleted: localhost/base:latest
331+
332+
# All tags are now gone
333+
$ crictl images
334+
IMAGE TAG IMAGE ID SIZE
335+
```
336+
296337
### Filter images
297338

298339
The following filters are available `--filter`, `-f`:

0 commit comments

Comments
 (0)