【问题标题】:How to check if a Docker image with a specific tag exist locally?如何检查本地是否存在带有特定标签的 Docker 镜像?
【发布时间】:2015-08-13 03:16:34
【问题描述】:

我想知道本地是否存在带有特定标签的 Docker 映像。如果 Docker 客户端本身无法执行此操作,我可以使用 bash 脚本。

只是为潜在的 bash 脚本提供一些提示,运行 docker images 命令的结果返回以下内容:

REPOSITORY                               TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
rabbitmq                                 latest              e8e654c05c91        5 weeks ago         143.5 MB
busybox                                  latest              8c2e06607696        6 weeks ago         2.433 MB
rabbitmq                                 3.4.4               a4fbaad9f996        11 weeks ago        131.5 MB

【问题讨论】:

    标签: bash docker


    【解决方案1】:

    我通常测试docker images -q的结果(如this script):

    if [[ "$(docker images -q myimage:mytag 2> /dev/null)" == "" ]]; then
      # do something
    fi
    

    但是由于docker images只接受REPOSITORY作为参数,你需要在标签上grep,而不使用-q

    docker images 现在接受标签(docker 1.8+)[REPOSITORY[:TAG]]

    下面提到的另一种方法是使用docker inspect
    但是对于 docker 17+,图像的语法是:docker image inspect(在不存在的图像上,exit status will be non-0

    正如iTaybthe comments 中所指出的:

    • docker images -q 方法在具有大量图像的机器上会变得非常慢。在 6500 张图像的机器上运行需要 44 秒。
    • docker image inspect 立即返回。

    Henry Blyth 在 cmets 中指出:

    如果你使用docker image inspect my_image:my_tag,并且你想忽略输出,你可以添加--format="ignore me",它会直接打印出来。

    您也可以通过添加 >/dev/null 来重定向标准输出,但是,如果您不能在脚本中这样做,那么格式选项可以正常工作。

    【讨论】:

    • 嗯不确定这是否适用于标签?当我执行“docker images -q rabbitmq”时,它返回“e8e654c05c91 and a4fbaad9f996”,但如果我执行“docker images -q rabbitmq:3.4.4”,即使标签存在,也不会返回任何内容。
    • @Johan 即使标签存在于本地?
    • @Johan 我只是仔细检查了一遍,docker images 参数确实只接受了 repo,而不是标签。我已编辑答案以提出替代解决方案。
    • 谢谢,这似乎有效。但也许你应该编辑你的答案并在我接受之前从“myimage:mytag”中删除“:mytag”?
    • @HenryBlyth 感谢您的反馈。我已将您的评论包含在答案中以提高知名度。
    【解决方案2】:

    试试docker inspect,例如:

    $ docker inspect --type=image treeder/hello.rb:nada
    Error: No such image: treeder/hello.rb:nada
    []
    

    但是现在有了一个存在的图像,你会得到一堆信息,例如:

    $ docker inspect --type=image treeder/hello.rb:latest
    [
    {
        "Id": "85c5116a2835521de2c52f10ab5dda0ff002a4a12aa476c141aace9bc67f43ad",
        "Parent": "ecf63f5eb5e89e5974875da3998d72abc0d3d0e4ae2354887fffba037b356ad5",
        "Comment": "",
        "Created": "2015-09-23T22:06:38.86684783Z",
        ...
    }
    ]
    

    而且它是一个不错的 json 格式。

    【讨论】:

    • 这是最适合编写脚本的答案。
    • 确实,imagesps 命令总是以 0 退出,inspect 很简单:docker inspect "${image_id}:${image_tag}" > /dev/null 2>&1 || echo "does not exist!"
    • docker inspect 很棒,因为在不存在图像时返回非零代码。
    • 这也比docker images -q快得多。
    • 如果你想在你的脚本中禁止输出:if ! docker inspect <CONDITION> >> temp_docker-inspect.txt; then ...
    【解决方案3】:

    tldr:

    docker image inspect myimage:mytag
    

    通过演示的方式...

    成功,找到图片:

    $ docker image pull busybox:latest
    latest: Pulling from library/busybox
    Digest: sha256:32f093055929dbc23dec4d03e09dfe971f5973a9ca5cf059cbfb644c206aa83f
    Status: Image is up to date for busybox:latest
    
    $ docker image inspect busybox:latest >/dev/null 2>&1 && echo yes || echo no
    yes
    

    失败,图片丢失:

    $ docker image rm busybox:latest
    Untagged: busybox:latest
    Untagged: busybox@sha256:32f093055929dbc23dec4d03e09dfe971f5973a9ca5cf059cbfb644c206aa83f
    
    $ docker image inspect busybox:latest >/dev/null 2>&1 && echo yes || echo no
    no
    

    参考:

    https://docs.docker.com/engine/reference/commandline/image_inspect/

    【讨论】:

    • 这很简单,快速且兼容未来。我会坚持这个解决方案。
    • 更具体地说,为图像指定--type image,或为现有容器指定--type container
    • @smac89,我不熟悉那个选项。 ``` $ docker --version Docker version 20.10.6, build 370c289 $ docker image inspect --help 用法:docker image inspect [OPTIONS] IMAGE [IMAGE...] 显示一个或多个图像的详细信息 选项:-f , --format string 使用给定的 Go 模板格式化输出```
    • 哦,哎呀,我在做docker inspect,而不是docker image inspect
    【解决方案4】:

    你可以像下面这样使用:

    [ -n "$(docker images -q someimage:sometag)" ] || echo "does not exist"
    

    或者:

    [ -z "$(docker images -q someimage:sometag)" ] || echo "already exists"
    

    【讨论】:

    • 不起作用,至少在macOS上,返回值始终为0。
    • 代码正确,适用于linux。我唯一要添加的是子shell命令的引号
    • @GaborCsardi 这个适用于 MacOS:[[ -z "$(docker images -q someimage:sometag)" ]] || echo "exists"[[ -n "$(docker images -q someimage:sometag)" ]] || echo "doesn't exist"。编辑答案。现在应该可以正常工作了。 Gabor,你能确认一下吗?
    【解决方案5】:

    在上面Vonc's answer 的帮助下,我创建了以下名为check.sh 的bash 脚本:

    #!/bin/bash
    image_and_tag="$1"
    image_and_tag_array=(${image_and_tag//:/ })
    if [[ "$(docker images ${image_and_tag_array[0]} | grep ${image_and_tag_array[1]} 2> /dev/null)" != "" ]]; then
      echo "exists"
    else
      echo "doesn't exist"
    fi
    

    将其用于现有图像和标签将打印exists,例如:

    ./check.sh rabbitmq:3.4.4
    

    将它用于不存在的图像和标签将打印doesn't exist,例如:

    ./check.sh rabbitmq:3.4.3
    

    【讨论】:

      【解决方案6】:

      如果您尝试从 docker 注册表中搜索 docker 映像,我想检查 docker 映像是否存在的最简单方法是使用 Docker V2 REST API Tags list service

      例子:-

      curl $CURLOPTS -H "Authorization: Bearer $token" "https://hub.docker.com:4443/v2/your-repo-name/tags/list"
      

      如果上面的结果返回 200Ok 并带有图像标签列表,那么我们知道图像存在

      {"name":"your-repo-name","tags":["1.0.0.1533677221","1.0.0.1533740305","1.0.0.1535659921","1.0.0.1535665433","latest"]}
      

      如果你看到类似的东西

      {"errors":[{"code":"NAME_UNKNOWN","message":"repository name not known to registry","detail":{"name":"your-repo-name"}}]} 
      

      那么你肯定知道该图像不存在。

      【讨论】:

        【解决方案7】:

        使用test

        if test ! -z "$(docker images -q <name:tag>)"; then
          echo "Exist"
        fi
        

        或一行

        test ! -z "$(docker images -q <name:tag>)" &&  echo exist
        

        【讨论】:

          【解决方案8】:

          在 bash 脚本中,我这样做是为了通过标签检查图像是否存在:

          IMAGE_NAME="mysql:5.6"
          
          if docker image ls -a "$IMAGE_NAME" | grep -Fq "$IMAGE_NAME" 1>/dev/null; then
          echo "could found image $IMAGE_NAME..."
          fi
          

          上面的示例脚本检查是否存在带有 5.6 标签的 mysql 映像。如果您只想检查是否存在任何没有特定版本的 mysql 映像,那么只需传递不带标签的存储库名称:

          IMAGE_NAME="mysql"
          

          【讨论】:

            【解决方案9】:

            受上述@rubicks 回复的启发。

            检查图像是否已经存在

            image_name_tag="alpine:3.13.3"
            
            docker image inspect ${image_name_tag} > /dev/null
            echo $?
            

            如果图片不存在则拉取

            docker image inspect ${image_name_tag} > /dev/null || docker  pull ${image_name_tag}
            

            演示执行

            # image_name_tag="alpine:3.13.3"
            # 
            # docker image inspect ${image_name_tag} > /dev/null
            echo $?
            Error: No such image: alpine:3.13.3
            # echo $?
            1
            # docker image inspect ${image_name_tag} > /dev/null || docker  pull ${image_name_tag}
            Error: No such image: alpine:3.13.3
            3.13.3: Pulling from library/alpine
            9aae54b2144e: Pull complete 
            Digest: sha256:826f70e0ac33e99a72cf20fb0571245a8fee52d68cb26d8bc58e53bfa65dcdfa
            Status: Downloaded newer image for alpine:3.13.3
            docker.io/library/alpine:3.13.3
            # docker image inspect ${image_name_tag} > /dev/null || docker  pull ${image_name_tag}
            $ 
            

            【讨论】:

              【解决方案10】:

              我只是给非常好的读者一点点:

              构建

              #!/bin/bash -e
              docker build -t smpp-gateway smpp
              (if  [ $(docker ps -a | grep smpp-gateway | cut -d " " -f1) ]; then \
                echo $(docker rm -f smpp-gateway); \
              else \
                echo OK; \
              fi;);
              docker run --restart always -d --network="host" --name smpp-gateway smpp-gateway:latest
              

              观看

              docker logs --tail 50 --follow --timestamps smpp-gateway
              

              运行

              sudo docker exec -it \
              $(sudo docker ps | grep "smpp-gateway:latest" | cut -d " " -f1) \
              /bin/bash
              

              【讨论】:

                【解决方案11】:

                对于特定的标签名称

                $ docker images  --filter reference='<REPOSITORY>:TAG'
                

                for "like 子句" tagname:my_image_tag --> start my_ima*

                $ docker images  --filter reference='<REPOSITORY>:my_ima*'
                

                如果你想要一些“图像”,例如删除所有图像标签开始“my_ima”试试这个

                docker rmi -f $(docker images -q  --filter reference='myreponame:my_ima*')
                

                【讨论】:

                • 如果镜像不存在,退出码依然为0。因此,它与在脚本中使用无关,仅对人类(谁可以使用更通用的docker镜像| grep 也是)
                【解决方案12】:

                我认为这个功能应该在docker build 命令中实现(使用标志?),这样可以避免大量的代码重复。

                我在名为docker_build 的包装函数中使用了与accepted answer 相同的条件,以便在调用原始docker build 命令之前进行必要的检查。

                # Usage: docker_build <...> (instead of docker build)
                
                docker_build()
                {
                    local arguments=("$@")
                    local index
                    for (( index=0; index<$#; index++ )); do
                        case ${arguments[index]} in
                            --tag)
                                local tag=${arguments[index+1]}
                                if [[ ! -z $(docker images -q "${tag}" 2> /dev/null) ]]; then
                                    echo "Image ${tag} already exists."
                                    return
                                fi
                                ;;
                        esac
                    done
                    command docker build "$@"
                }
                

                免责声明:这不适用于生产,因为它仅适用于长格式的空格分隔参数,即--tag hello-world:latest。此外,这只是修改了docker build 命令,所有其他命令保持不变。如果有人有改进,请告诉我。

                我之所以愿意分享这个 sn-p,是因为在 bash-functions 中包装标准命令以避免代码重复的想法似乎比编写包装语句更优雅和可扩展。

                【讨论】:

                  【解决方案13】:

                  我喜欢这个,因为它简洁并且具有正确的语义。如果图像存在,那是真的,还有什么比这更容易的呢?

                  if [ $(docker image ls ${build_env} --format="true") ] ; 
                  then
                   echo "does exist"
                  fi
                  

                  【讨论】:

                    猜你喜欢
                    • 2021-04-25
                    • 2021-07-30
                    • 2018-06-11
                    • 2020-07-08
                    • 1970-01-01
                    • 2018-09-14
                    • 2017-11-27
                    • 2019-08-16
                    • 2021-07-28
                    相关资源
                    最近更新 更多