我如何判断我是否';m从脚本登录到私有Docker注册表?

我如何判断我是否';m从脚本登录到私有Docker注册表?,docker,Docker,如何判断我是否从脚本登录到私有Docker注册表服务器?换句话说,docker login some.registry.com是否已成功运行(并且仍然有效) 注意:我询问的是一个任意的私有注册表,而不是docker.io注册表。如果docker登录成功,您将在主目录(~/.docker/)上找到一个.docker文件夹,其中包含一个带有凭据的config.json文件 否则,您将在登录时出错 注意:docker通过查看注册表名来确定要使用的凭据: 如果你这样做 docker pull myreg

如何判断我是否从脚本登录到私有Docker注册表服务器?换句话说,
docker login some.registry.com
是否已成功运行(并且仍然有效)


注意:我询问的是一个任意的私有注册表,而不是
docker.io
注册表。

如果docker登录成功,您将在主目录(
~/.docker/
)上找到一个
.docker
文件夹,其中包含一个带有凭据的
config.json
文件

否则,您将在登录时出错

注意:docker通过查看注册表名来确定要使用的凭据:

如果你这样做

docker pull myregistry.com/myimage:tag

docker将查看您是否已登录,如果未登录,docker将检查您是否具有注册表
myregistry.com
的凭据,并使用这些凭据登录


如果没有,您将得到一个权限错误

,这有点不正常,但它在大多数情况下对我有效:

if ! grep -q "my.private.registry.com" ~/.docker/config.json ; then
    docker login "my.private.registry.com"
fi
基本上,您可以搜索
~/.docker/config.json
中是否有“my.private.registry.com”的记录。但是,如果会话已过期,此检查将无法捕获它。

当您执行

Docker login <private registry> -u <user> -p <password> 
如果你成功了

在shell脚本中,您可以只查看收到的响应,如果它不等于0,则表示您登录失败

sudo docker login <registry> -u <uname> -p <password>
if [ $? -ne 0 ]; then
    echo Login failed!
else
    echo Login OK!
fi
sudo docker登录-u-p
如果[$?-ne 0];然后
echo登录失败!
其他的
回音登录好!
fi

这有点不对劲,我认为在docker获得检查登录的命令之前,不会有任何好的解决方案。
您可以在bash脚本中尝试以x秒的超时时间登录,如果您未登录,该命令将尝试提示输入用户名,然后将以状态
124
超时。如果您确实已登录,它将使用保存凭据再次登录,并继续执行状态
0

#/bin/bash
超时-s SIGKILL 3s docker登录some.registry.com>/dev/null 2>&1
如果[$?-等式0]
然后
echo已登录!
其他的
echo未登录。。。
fi

如果您必须检查本地系统,则不可能知道

。。。确保docker存储的凭据仍然有效的唯一方法是执行一个操作,该操作将使这些凭据呈现给注册表,并查看注册表是否接受它们

如果您想使用docker CLI获得答案,则可以使用@matanper建议的“再次登录”,如果您仍然拥有有效的凭据,该建议将自动完成

另一种方法是尝试提取已知不存在的图像,无论是否登录,该图像都会显示不同的错误消息,例如:

# NO VALID LOGIN:

$ docker pull 999999999999.dkr.ecr.us-west-2.amazonaws.com/this/image:does_not_exist
Error response from daemon: pull access denied for 999999999999.dkr.ecr.us-west-2.amazonaws.com/this/image, repository does not exist or may require 'docker login'

# WITH VALID LOGIN:

$ docker pull 999999999999.dkr.ecr.us-west-2.amazonaws.com/this/image:does_not_exist
Error response from daemon: manifest for 999999999999.dkr.ecr.us-west-2.amazonaws.com/this/image:does_not_exist not found
(假设您不想
拉入
,因为您不想有任何延迟或大数据传输,所以上述方法仍然是“ok”)

过去,当docker总是将凭证存储在
~/.docker/config.json
(或您的操作系统的等效文件)中时,您可以解析该文件以获取当前存储的凭证,然后使用
curl
或类似工具运行凭证。然而,最近的docker版本将凭证存储在主机操作系统特定的存储中(例如Mac OS X上的钥匙链),因此这不再是一种可移植的方法。如果可移植性不重要,您仍然可以尝试类似的方法-在
config.json
中的散列只是base64编码的用户名和密码,用冒号分隔,这是HTTP basic auth的标准,例如在linux上,用
jq
解析json,用
base64
解码base64:

$  cat ~/.docker/config.json  | jq -r '.auths["registry.example.com"].auth' | base64 -d

username:password
因此,使用
curl
使用注册表列表操作来完成该操作:

REGISTRY="registry.example.com"

CREDENTIALS="$(cat ~/.docker/config.json | jq -r ".auths[\"${REGISTRY}\"].auth" | base64 -d)"

curl -sSf --max-time 3 --user "${CREDENTIALS}" "https://${REGISTRY}/v2/_catalog"
将返回退出代码零,如果凭据良好,则返回JSON响应;或非零退出代码(如果不是)

{
  "repositories": [
    "jamesjj/test-image",
    "jamesjj/other-image",
    ...
    ...
}
注意:解析JSON时,注册表地址键可能包括也可能不包括模式
https://
,这取决于原始登录的执行方式,因此
cat~/.docker/config.JSON | jq-r.auths[\“${registry}\”].auth“| base64-d)”
…可能需要:
cat~/.docker/config.json | jq-r.auths[\“https://${REGISTRY}\\”].auth“| base64-d)”
您可以解析
.docker/config.json
并尝试手动连接到文件中指定的每个注册表。该文件包含注册表地址和编码的用户名和密码,因此您可以编写此过程的脚本。您可以使用类似的库来实现这一点

然后:

import base64
import docker_registry_client
import json
import os.path

def get_authed_registries():
  result = []
  config_path = os.path.expanduser("~/.docker/config.json")
  if not os.path.isfile(config_path):
    print("No docker config")
    return []

  docker_config = json.load(open(config_path))

  for registry, auth in docker_config.get("auths", {}).items():
    username, password = base64.b64decode(auth["auth"]).decode("utf-8").split(":", 1)
    if not registry:
      registry = "https://index.docker.io/v1/"
    if not registry.startswith("http"):
      registry = "https://" + registry
    try:
      rc = docker_registry_client.DockerRegistryClient(registry, username=username, password=password)
      result.append(registry)
    except Exception, e:
      print(registry, "failed:", e)

  return result


get_authed_registries()
有几点需要注意:

  • 如果您使用的是一个
  • 在Python2.7上测试。可能需要对Python3进行一些小的调整
  • 此代码用于身份验证,但对注册表的任何进一步操作都会失败。您需要从主机名中删除API版本(
    /v1
    /v2
    ,等等)
  • 代码假定所有注册表都是HTTPS(除非在
    config.json
    中另有规定)
  • 更正确的版本可能会删除除主机名以外的任何内容,并尝试v1和v2

这就是说,我能够获得登录注册表的列表,它正确地忽略了过期的ECR登录。

我相信错误消息会因注册表实现而异。但是,我自己的技术是提取一个不存在的图像并解析任何错误消息:

$!/bin/sh
repo="$1"
msg=$(docker pull ${repo}/missing:missing 2>&1)
case "$msg" in
  *"requested access to the resource is denied"*|*"pull access denied"*)
    echo "Logged out";;
  *"manifest unknown"*|*"not found"*)
    echo "Logged in, or read access for anonymous allowed";;
  *"Pulling from"*)
    echo "Missing image was not so missing after all?";;
  *) 
    echo "Unknown message: $msg";;
esac
这已经通过docker standalone注册表和docker_auth进行了测试。您需要使用可能遇到的注册表进行测试

如果您的注册表服务器允许匿名拉取,并且您希望验证推取是否可行,则可以创建一个伪空映像,并用该映像的推取替换该拉取。例如

#!/bin/sh
repo=$1
# note, I do not like the "." here, better to change it to an empty directory
# see "mktemp" for an option if you cannot make your own empty directory somewhere
docker build -t "${repo}/empty:test" -f - . <<EODF
FROM scratch
EODF
msg=$(docker push "${repo}/empty:test" 2>&1)
rc=$?
if [ "$rc" = "0" ]; then
  echo "Access granted to push"
else
  case "$msg" in
    *"requested access to the resource is denied"*)
      echo "Access denied";;
    *) 
      echo "Unknown error message: $msg";;
  esac
fi
#/垃圾箱/垃圾箱
回购=1美元
#注意,我不喜欢这里的“.”,最好把它改成一个空目录
#如果您不能在某个地方创建自己的空目录,请参阅“mktemp”以获取选项

docker构建-t“${repo}/empty:test”-f-。可能重复的“否”,仅适用于docker.io注册表。您是绝对的
$!/bin/sh
repo="$1"
msg=$(docker pull ${repo}/missing:missing 2>&1)
case "$msg" in
  *"requested access to the resource is denied"*|*"pull access denied"*)
    echo "Logged out";;
  *"manifest unknown"*|*"not found"*)
    echo "Logged in, or read access for anonymous allowed";;
  *"Pulling from"*)
    echo "Missing image was not so missing after all?";;
  *) 
    echo "Unknown message: $msg";;
esac
#!/bin/sh
repo=$1
# note, I do not like the "." here, better to change it to an empty directory
# see "mktemp" for an option if you cannot make your own empty directory somewhere
docker build -t "${repo}/empty:test" -f - . <<EODF
FROM scratch
EODF
msg=$(docker push "${repo}/empty:test" 2>&1)
rc=$?
if [ "$rc" = "0" ]; then
  echo "Access granted to push"
else
  case "$msg" in
    *"requested access to the resource is denied"*)
      echo "Access denied";;
    *) 
      echo "Unknown error message: $msg";;
  esac
fi