Как я могу использовать API реестра Docker для получения информации о контейнере? Получение НЕСАНКЦИОНИРОВАННО

Некоторое время назад я наткнулся на статью под названием " Проверка образов докеров", не тянув их, чтобы вникнуть в суть специфических вызовов API, необходимых для выполнения docker inspect с остальными звонками. Однако мне интересно, возможно, что-то изменилось с API реестра Docker с момента написания этой статьи.

В статье рассказывается, что вам нужно сделать три вызова REST, чтобы получить информацию о контейнере. В случае общедоступного реестра Docker они выглядят следующим образом:

  1. GET-запрос к auth.docker.io для получения токена

    curl "https://auth.docker.io/token?scope=repository:<image>:pull&service=registry.docker.io"
    

    В этом случае image может быть что-то вроде nginx или же docker - в основном, какое бы изображение вы ни искали. Этот вызов REST возвращает токен для использования в последующих запросах.

  2. GET-запрос для получения списков манифестов

    curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json"
    -H "Authorization: Bearer <token-from-step-1>"
    "https://registry-1.docker.io/v2/<image>/manifests/<tag>"
    

    Вот image такой же, как в шаге 1, и tag может быть что-то вроде latest, Этот вызов возвращает некоторый JSON; ключ в том, что нам нужно извлечь значение в .config.digest, Это строка дайджеста, которую мы используем в последнем запросе.

  3. Наконец GET-запрос для получения конфигурации контейнера, используя дайджест, полученный на шаге 2

    curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json"
    -H "Authorization: Bearer <token-from-step-1>"
    "https://registry-1.docker.io/v2/<image>/blobs/<digest-from-step-2>"
    

    Это возвращает некоторый JSON, и поле, о котором я забочусь, .config

Я смог успешно проверить это в частном реестре Docker, хотя там мне пришлось сделать что-то другое для аутентификации. Однако у меня возникает противоположная проблема, когда я пытаюсь следовать руководству (которое я обрисовал в общих чертах в этих шагах выше) для общедоступного реестра Docker: шаг 1 дает мне токен, но этот токен бесполезен. Всякий раз, когда я пытаюсь использовать это, в Шагах 2 или 3, я получаю это обратно:

{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"repository","Class":"","Name":"docker","Action":"pull"}]}]}

Любые идеи о том, как заставить это работать?

2 ответа

Решение

Используя следующие шаги вы можете получить конфигурацию любого общедоступного контейнера-образа.

  1. Получите соответствующий токен для изображения. Обратите внимание, что вы должны указать полное имя изображения (официальные изображения используют library хранилище). Таким образом, изображение NGINX должно упоминаться как: library/nginx,

    curl \
        --silent \
        "https://auth.docker.io/token?scope=repository:library/nginx:pull&service=registry.docker.io" \
        | jq -r '.token'
    

    Для краткости токен сокращен: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXV...

  2. Получите дайджест изображения из манифеста. Для этого запроса также необходимо указать допустимый тег (в этом примере используется latest тег).

    curl \
        --silent \
        --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \
        --header "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXV..." \
        "https://registry-1.docker.io/v2/library/nginx/manifests/latest" \
        | jq -r '.config.digest'
    

    sha256: 2bcb04bdb83f7c5dc30f0edaca1609a716bda1c7d2244d4f5fbbdfef33da366c

  3. Наконец, получите конфигурацию контейнера, используя следующий запрос. В URL должен быть указан дайджест из второго шага.

    curl \
        --silent \
        --location \
        --header "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXV..." \
        "https://registry-1.docker.io/v2/library/nginx/blobs/sha256:2bcb04bdb83f7c5dc30f0edaca1609a716bda1c7d2244d4f5fbbdfef33da366c" \
        | jq -r '.container_config'
    

    Вывод сокращен для краткости:

    {
        "Hostname": "6c02a05b3d09",
        "Env": [
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
            "NGINX_VERSION=1.15.10-1~stretch",
            "NJS_VERSION=1.15.10.0.3.0-1~stretch"
        ],
        "Labels": {
            "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
        },
        "StopSignal": "SIGTERM"
    }
    

В статье говорится, что вам нужно сделать три вызова REST, чтобы получить информацию о контейнере.

об образе

Наконец, запрос GET для получения конфигурации контейнера.

конфигурация изображения

Скрипт, отображающий конфигурацию образа. Он работает с частными реестрами и Docker Hub. Для базовых регистров аутентификации вам необходимо указать второй аргумент (user:pass).

      #!/usr/bin/env bash
set -eu
image=$1
creds=${2-}

# https://github.com/moby/moby/blob/v20.10.18/vendor/github.com/docker/distribution/reference/normalize.go#L29-L57
# https://github.com/moby/moby/blob/v20.10.18/vendor/github.com/docker/distribution/reference/normalize.go#L88-L105
registry=${image%%/*}
if [ "$registry" = "$image" ] \
|| { [ "`expr index "$registry" .:`" = 0 ] && [ "$registry" != localhost ]; }; then
    registry=docker.io
else
    image=${image#*/}
fi
if [ "$registry" = docker.io ] && [ "`expr index "$image" /`" = 0 ]; then
    image=library/$image
fi
if [ "`expr index "$image" :`" = 0 ]; then
    tag=latest
else
    tag=${image#*:}
    image=${image%:*}
fi
if [ "$registry" = docker.io ]; then
    registry=https://registry-1.docker.io
elif ! [[ "$registry" =~ ^localhost(:[0-9]+)$ ]]; then
    registry=https://$registry
fi

r=`curl -sS "$registry/v2/" \
    -o /dev/null \
    -w '%{http_code}:%header{www-authenticate}'`
http_code=`echo "$r" | cut -d: -f1`
curl_args=(-sS -H 'Accept: application/vnd.docker.distribution.manifest.v2+json')
if [ "$http_code" = 401 ]; then
    if [ "$registry" = https://registry-1.docker.io ]; then
        header_www_authenticate=`echo "$r" | cut -d: -f2-`
        header_www_authenticate=`echo "$header_www_authenticate" | sed -E 's/^Bearer +//'`
        split_into_lines() {
            sed -Ee :1 -e 's/^(([^",]|"([^"]|\")*")*),/\1\n/; t1'
        }
        header_www_authenticate=`echo "$header_www_authenticate" | split_into_lines`
        extract_value() {
            sed -E 's/^[^=]+="(([^"]|\")*)"$/\1/; s/\\(.)/\1/g'
        }
        realm=$(echo "$header_www_authenticate" | grep '^realm=' | extract_value)
        service=$(echo "$header_www_authenticate" | grep '^service=' | extract_value)
        scope=repository:$image:pull
        token=`curl -sS "$realm?service=$service&scope=$scope" | jq -r .token`
        curl_args+=(-H "Authorization: Bearer $token")
    else
        curl_args+=(-u "$creds")
    fi
fi
manifest=`curl "${curl_args[@]}" "$registry/v2/$image/manifests/$tag"`
config_digest=`echo "$manifest" | jq -r .config.digest`
curl "${curl_args[@]}" -L "$registry/v2/$image/blobs/$config_digest" | jq -C

Использование:

      $ ./image-config.sh ruby
$ ./image-config.sh library/ruby            # same as the one above
$ ./image-config.sh docker.io/library/ruby  # same as the previous two
$ ./image-config.sh docker.io/library/ruby:3.0.4
$ ./image-config.sh myregistry.com/hello-world testuser:testpassword
$ ./image-config.sh localhost:5000/hello-world

Пара замечаний по использованию API:

  • Реестр представляет собой набор репозиториев. Подумайте о Гитхабе. Обычно имена репозиториев имеют формуuser/name(напримерnginxproxy/nginx-proxy). А вот с официальными репозиториями (которые все на самом деле начинаются сlibrary/) первый сегмент может быть опущен (library/ruby->ruby). Также может быть только один сегмент (например, в частных реестрах), и иногда только первая часть называется репозиторием ( пример ). Или второй.
  • Репозиторий — это набор изображений. Некоторые из них помечены. Изображения без тегов обычно появляются, когда вы отправляете новую версию изображения с тем же тегом.
  • Старая, но, может быть, несколько актуальная актуальная статья (по крайней мере, начало).
  • URL-адрес реестра Docker Hub см. в этом ответе .
  • Не ожидайте, что все в спецификации будет работать. Например, Docker Hub не реализует/v2/_catalogмаршрут.
Другие вопросы по тегам