Check if image:tag combination already exists on docker hub

纵饮孤独 提交于 2019-11-27 20:04:14

Please try this one

function docker_tag_exists() {
    curl --silent -f -lSL https://index.docker.io/v1/repositories/$1/tags/$2 > /dev/null
}

if docker_tag_exists library/nginx 1.7.5; then
    echo exist
else 
    echo not exists
fi

Update:

In case of usage Docker Registry v2 (based on this):

# set username and password
UNAME="user"
UPASS="password"

function docker_tag_exists() {
    TOKEN=$(curl -s -H "Content-Type: application/json" -X POST -d '{"username": "'${UNAME}'", "password": "'${UPASS}'"}' https://hub.docker.com/v2/users/login/ | jq -r .token)
    EXISTS=$(curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/$1/tags/?page_size=10000 | jq -r "[.results | .[] | .name == \"$2\"] | any")
    test $EXISTS = true
}

if docker_tag_exists library/nginx 1.7.5; then
    echo exist
else 
    echo not exists
fi

This is the solution I use with gitlab using the docker:stable image.

Make sure experimental client-features are enabled:

echo '{"experimental": "enabled"}' > ~/.docker/config.json

This will also overwrite your config. If that is not an option you need to do that manually or use jq, sed or whatever you have available.

Login

docker login -u $USER -p $PASSWORD $REGISTRY

Check whether it's there:

docker manifest inspect $IMGNAME:$IMGTAG > /dev/null ; echo $?

docker will return 0 on success or 1 on failure.

To build on morty's answer, notice that docker supports setting the experimental flag using environment variable:

DOCKER_CLI_EXPERIMENTAL Enable experimental features for the cli (e.g. enabled or disabled)

The snippet therefore becomes:

tag=something
if DOCKER_CLI_EXPERIMENTAL=enabled docker manifest inspect $image:$tag >/dev/null; then
    Do nothing
else
    Build and push docker image with that tag
fi

Here's a Bash function that will help:

docker_image_exists() {
  local image_full_name="$1"; shift
  local wait_time="${1:-5}"
  local search_term='Pulling|is up to date|not found'
  local result="$((timeout --preserve-status "$wait_time" docker 2>&1 pull "$image_full_name" &) | grep -v 'Pulling repository' | egrep -o "$search_term")"
  test "$result" || { echo "Timed out too soon. Try using a wait_time greater than $wait_time..."; return 1 ;}
  echo $result | grep -vq 'not found'
}

Usage example:

docker_image_exists elifarley/docker-dev-env:alpine-sshd && \
  echo EXISTS || \
  echo "Image does not exist"

I like solutions based on docker.

This oneliner is what I use in our CI:

 docker run --rm anoxis/registry-cli -l user:password -r registry-url -i docker-name | grep -q docker-tag || echo do something if not found

Easiest:

docker pull alpine:invalid > /dev/null && echo "success" || echo "failed"

Pulls & prints success if image exists, or prints failed if it doesn't:

You can even export it in a var if using in bash script:

Just a small improvement of Evgeny Oskin's solution. When it comes to a user repo that hasn't been created yet, jq says that it "Cannot iterate over null". To overcome it. one can skip not present blocks with ? Here is a modification to above mentioned solution that is applicable to a public repo in particular:

#!/usr/bin/env bash

function docker_image_tag_exists() {
    EXISTS=$(curl -s https://hub.docker.com/v2/repositories/$1/tags/?page_size=10000 | jq -r "[.results? | .[]? | .name == \"$2\"] | any")
    test ${EXISTS} = true
}

if docker_image_tag_exists $1 $2; then
    echo "true"
else
    echo "false"
fi

I was struggling getting this to work for a private docker hub repository and finally decided to write a ruby script instead, which works as of today. Feel free to use!

#!/usr/bin/env ruby
require 'base64'
require 'net/http'
require 'uri'

def docker_tag_exists? repo, tag
  auth_string = Base64.strict_encode64 "#{ENV['DOCKER_USER']}:#{ENV['DOCKER_PASSWORD']}"
  uri = URI.parse("https://registry.hub.docker.com/v1/repositories/#{repo}/tags/#{tag}")
  request = Net::HTTP::Get.new(uri)
  request['Authorization'] = "Basic #{auth_string}"
  request['Accept'] = 'application/json'
  request['Content-Type'] = 'application/json'
  response = Net::HTTP.start(request.uri.hostname, request.uri.port, use_ssl: true) do |http|
    http.request(request)
  end
  (response.body == 'Tag not found') ? 0 : 1
end

exit docker_tag_exists? ARGV[0], ARGV[1]

Note: you need to specify DOCKER_USER and DOCKER_PASSWORD when calling this like...

DOCKER_USER=XXX DOCKER_PASSWORD=XXX config/docker/docker_hub.rb "NAMESPACE/REPO" "TAG" && echo 'latest'

This line would print out 'latest', if authentication is successful and the specified tag does not exists! I was using this in my Vagrantfile when trying to fetch a tag based on the current git branch:

git rev-parse --symbolic-full-name --abbrev-ref HEAD

You could just try pulling and see if you're up to date (You may want to tag your local image first though in case the remote is newer):

docker pull deepdriveio/deepdrive:env-3.0
env-3.0: Pulling from deepdriveio/deepdrive
Digest: sha256:3b6b6514f79a551b47896f908a2de00b55df1db22f5908c8436feaa12310dfa3
Status: Image is up to date for deepdriveio/deepdrive:env-3.0

Have you tried something like that, simply trying to pull the tag and deciding to push or not according to the return code?

#! /bin/bash

if docker pull hello-world:linux > /dev/null; then
  echo "already exist -> do not push"
else
  echo "does not exist -> push"
fi
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!