簡體   English   中英

檢查圖像:docker 集線器上是否已存在標簽組合

[英]Check if image:tag combination already exists on docker hub

作為 bash 腳本的一部分,我想檢查 docker 集線器上是否存在特定的 docker 圖像:標簽組合。 此外,它將是一個私有存儲庫。

即偽代碼將是這樣的:

tag = something
if image:tag already exists on docker hub:
    Do nothing
else
    Build and push docker image with that tag

更新:無 Docker 解決方案見下文

使用 Docker

這是我使用 docker:stable 圖像與 gitlab 一起使用的解決方案。

登錄

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

檢查它是否存在:

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

docker 將返回 0 成功或 1 失敗。

如果您收到警告:更新 Docker 或啟用實驗性客戶端功能

將環境變量DOCKER_CLI_EXPERIMENTAL設置為enabled (參見下面 Matěj 的回答)

或者調整配置(原始答案):

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

這也將覆蓋您的配置。 如果這不是一個選項,您需要手動執行或使用jqsed或任何可用的東西。

更新:如果您無權訪問 docker-daemon,例如因為您正在使用docker中的 kaniko 構建 docker 映像,您可以使用 Harbor 提供的registry-api 腳本 請注意,它們是 python2。

請試試這個

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

更新:

如果使用 Docker Registry v2(基於):

# 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)
    curl --silent -f --head -lL https://hub.docker.com/v2/repositories/$1/tags/$2/ > /dev/null
}

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

為了建立morty答案,請注意 docker 支持使用環境變量設置實驗標志

DOCKER_CLI_EXPERIMENTAL為 cli 啟用實驗性功能(例如enableddisabled

因此,片段變為:

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

最簡單的:

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

如果圖像存在則拉取並打印成功,如果不存在則打印失敗

如果在 bash 腳本中使用,您甚至可以將其導出為 var:

在此處輸入圖像描述

請注意,如果圖像存在,這將拉取圖像。 在使用此解決方案之前,請注意間接費用。

我有一個 docker private repo 在我的 LAN 上使用 registry:2、私有 CA 和基本身份驗證。

我只是查看了官方的 docker API 文檔( https://docs.docker.com/registry/spec/api/ )並提出了這個看起來非常優雅、易於調試、自定義並且對 CICD/腳本友好的解決方案.

curl --silent -i -u "demoadmin":"demopassword" https://mydockerrepo.local:5000/v2/rancher/pause/manifests/3.1 | grep "200 OK"

--silient 去掉了一些額外的文本
-i 是什么讓返回碼“200 OK”出現

如果存在返回碼為0,如果不存在返回碼為1,您可以驗證使用
重擊# 回聲 $?

這是一個有用的 Bash 函數:

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'
}

使用示例:

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

只是Evgeny Oskin 解決方案的一個小改進。 當涉及到尚未創建的用戶存儲庫時,jq 說它“無法迭代 null”。 去克服它。 可以跳過不存在的塊嗎? 這是對上述解決方案的修改,特別適用於公共回購:

#!/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

我一直在努力讓它為私人 docker hub 存儲庫工作,最后決定改寫一個 ruby​​ 腳本,它從今天開始就可以工作了。 隨意使用!

#!/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]

注意:您需要在調用時指定 DOCKER_USER 和 DOCKER_PASSWORD...

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

如果身份驗證成功並且指定的標簽不存在,此行將打印出“最新”! 當我嘗試基於當前 git 分支獲取標簽時,我在我的 Vagrantfile 中使用了它:

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

您可以嘗試拉取並查看您是否是最新的(您可能希望先標記本地圖像,以防遙控器更新):

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

上述所有選項都假定您可以使用用戶名/密碼進行身份驗證。 在很多情況下這樣做很不方便,例如在使用 Google Container Registry 時,首先要運行gcloud auth configure-docker gcr.io 該命令為 Docker 安裝了一個身份驗證幫助程序,您不希望自己管理該令牌。

一個支持這些 docker 身份驗證助手的工具,還允許獲取清單(如實驗性 Docker)是起重機

使用起重機的示例:

# you would have done this already
gcloud auth configure-docker gcr.io;

# ensure we have crane installed
which crane || (echo 'installing crane' && GO111MODULE=on go get -u github.com/google/go-containerregistry/cmd/crane)

# check manifest
crane manifest ubuntu || echo "does not exist"

我對這里的一些答案有很多問題。 我眼中最簡單的答案是來自@Evgeny Oskin 的公認答案。

卷曲一半有效,但由於某些原因,標簽中包含_-. 沒有被找到,我收到了 404。

最后我用以下解決方案修復了它:

curl -s -u "$DOCKERHUB_USER:$DOCKERHUB_PSWD" https://index.docker.io/v1/repositories/$company/$dockerHubRepo/tags | jq '.[] | select (.name == "$dockerImage")'

這將在 dockerhub 中獲取每個標簽的 json 文件,然后我們執行一些 jq 魔術來過濾圖像並檢查它是否確實存在。

如果圖像不存在,則返回的輸出將為空。

如果您要查詢 Hub 是否存在標簽,請確保使用 HEAD 而不是 GET 請求。 GET 請求計入您的速率限制。 專門針對 Docker Hub 執行此操作的腳本僅支持 Docker 媒體類型,以及受請求 IP 限制速率的匿名登錄,如下所示:

$ more ~/data/docker/registry-api/manifest-v2-head.sh 
#!/bin/sh

ref="${1:-library/ubuntu:latest}"
sha="${ref#*@}"
if [ "$sha" = "$ref" ]; then
  sha=""
fi
wosha="${ref%%@*}"
repo="${wosha%:*}"
tag="${wosha##*:}"
if [ "$tag" = "$wosha" ]; then
  tag="latest"
fi
api="application/vnd.docker.distribution.manifest.v2+json"
apil="application/vnd.docker.distribution.manifest.list.v2+json"
token=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:${repo}:pull" 
\
        | jq -r '.token')
curl -H "Accept: ${api}" -H "Accept: ${apil}" \
     -H "Authorization: Bearer $token" \
     -I -s "https://registry-1.docker.io/v2/${repo}/manifests/${sha:-$tag}" 

要在其他注冊表上工作、處理更多媒體類型(如 OCI 類型)和處理登錄,請使用諸如起重機、skopeo 或我自己的 regclient 之類的工具:

# the "image digest" command uses a HEAD instead of a GET
if regctl image digest registry.example.com/repo:tag >/dev/null 2>&1; then
  echo tag exists
else
  echo tag does not exist
fi

對於本地 docker 注冊表,您可以嘗試以下操作:

function docker_tag_exists() {
    curl --silent -f -lSL http://localhost:5000/v2/$1/manifests/$2 > /dev/null
}
if docker_tag_exists image_on_local latest; then
    echo exists
else
    echo not exists
fi

我喜歡基於 docker 的解決方案。

這個 oneliner 是我在我們的 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

您是否嘗試過類似的方法,只是嘗試拉標簽並根據返回碼決定是否推送?

#! /bin/bash

if docker pull hello-world:linux > /dev/null; then
  echo "already exist -> do not push"
else
  echo "does not exist -> push"
fi

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM