Работа с уведомлениями

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

Реестр поддерживает отправку уведомлений веб-перехватчиков в ответ на события, происходящие в реестре. Уведомления отправляются в ответ на запросы и запросы манифеста, а также запросы и запросы слоев. Данные действия сериализуются в события. События ставятся в очередь во внутреннюю систему широковещательной рассылки реестра, которая ставит в очередь и отправляет события в Конечные точки.

Workflow of registry notifications

Конечные точки

Уведомления отправляются на конечные точки через HTTP-запросы. Каждая настроенная конечная точка имеет изолированные очереди, конфигурацию повторных попыток и цели HTTP в каждом экземпляре реестра. Когда действие происходит в реестре, оно преобразуется в событие, которое помещается в очередь в памяти. Когда событие достигает конца очереди, к конечной точке отправляется http-запрос до тех пор, пока запрос не будет выполнен успешно. События отправляются последовательно на каждую конечную точку, но порядок не гарантируется.

Конфигурация

Чтобы настроить экземпляр реестра для отправки уведомлений на конечные точки, необходимо добавить их в конфигурацию. Далее следует простой пример:

notifications:
  endpoints:
    - name: alistener
      url: https://mylistener.example.com/event
      headers:
        Authorization: [Bearer <your token, if needed>]
      timeout: 500ms
      threshold: 5
      backoff: 1s

Вышеприведенное настроило бы реестр с конечной точкой для отправки событий в https://mylistener.example.com/event с заголовком «Авторизация: носитель». Время ожидания запроса истекает через 500 миллисекунд. Если подряд происходит 5 сбоев, реестр отключается на 1 секунду перед новой попыткой.

Подробнее о полях см. в документация по конфигурации.

Правильно настроенная конечная точка должна привести к сообщению журнала из реестра при запуске:

INFO[0000] configuring endpoint alistener (https://mylistener.example.com/event), timeout=500ms, headers=map[Authorization:[Bearer <your token if needed>]]  app.id=812bfeb2-62d6-43cf-b0c6-152f541618a3 environment=development service=registry

События

События имеют четко определенную структуру JSON и отправляются в виде тела запросов на уведомление. Одно или несколько событий отправляются в структуре, называемой конвертом. Каждое событие имеет уникальный идентификатор, который при необходимости можно использовать для уникальной идентификации входящих запросов. Наряду с этим действие снабжено целью, идентифицирующей объект, мутировавший во время события.

Поля, доступные в event, рассмотрены далее.

Поле

Тип

Описание

id

string

ID обеспечивает уникальный идентификатор события.

timestamp

Время

Отметка времени — это время, когда произошло событие.

действие

string

Действие указывает, какое действие включает в себя предоставленное событие.

цель

distribution.Descriptor

Target однозначно определяет цель события.

длина

int

Длина содержимого в байтах. То же, что и поле «Размер» в дескрипторе.

репозиторий

string

Репозиторий идентифицирует именованный репозиторий.

fromRepository

string

FromRepository определяет именованный репозиторий, из которого был смонтирован большой двоичный объект, если это необходимо.

URL

string

URL обеспечивает прямую ссылку на контент.

tag

string

Тег идентифицирует имя тега в событиях тега.

запрос

ЗапросЗапись

Запрос охватывает запрос, сгенерировавший событие.

актер

АктерЗапись.

Актер указывает агента, инициировавшего событие. В большинстве ситуаций это может происходить из контекста авторизации запроса.

источник

Исходная запись

Источник определяет узел реестра, сгенерировавший событие. Иными словами, в то время как актор «инициирует» событие, источник его «генерирует».

Далее приведён пример события JSON, отправленного в ответ на получение манифеста:

{
  "events": [
    {
      "id": "320678d8-ca14-430f-8bb6-4ca139cd83f7",
      "timestamp": "2016-03-09T14:44:26.402973972-08:00",
      "action": "pull",
      "target": {
        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
        "size": 708,
        "digest": "sha256:fea8895f450959fa676bcc1df0611ea93823a735a01205fd8622846041d0c7cf",
        "length": 708,
        "repository": "hello-world",
        "url": "http://192.168.100.227:5000/v2/hello-world/manifests/sha256:fea8895f450959fa676bcc1df0611ea93823a735a01205fd8622846041d0c7cf",
        "tag": "latest"
      },
      "request": {
        "id": "6df24a34-0959-4923-81ca-14f09767db19",
        "addr": "192.168.64.11:42961",
        "host": "192.168.100.227:5000",
        "method": "GET",
        "useragent": "curl/7.38.0"
      },
      "actor": {},
      "source": {
        "addr": "xtal.local:5000",
        "instanceID": "a53db899-3b4b-4a62-a067-8dd013beaca4"
      }
    }
  ]
}

Целевая структура событий, отправляемых при удалении манифестов и больших двоичных объектов, содержит подмножество данных, содержащихся в событиях Get и Put. В частности, отправляются только дайджест и репозиторий.

{
  "target": {
    "digest": "sha256:d89e1bee20d9cb344674e213b581f14fbd8e70274ecf9d10c514bab78a307845",
    "repository": "library/test"
  }
}

Примечание

Начиная с версии 2.1 поле length для целей событий устарело для поля size, что приводит цель в соответствие с общей номенклатурой. Оба будут по-прежнему установлены в обозримом будущем. Более новый код должен отдавать предпочтение size, но принимать любой из них.

Конверт

Конверт содержит одно или несколько событий со следующей структурой json:

{
  "events": [ "..." ]
}

Хотя события могут быть отправлены в одном и том же конверте, множество событий в этом конверте не имеет подразумеваемой связи. Например, реестр может сгруппировать несвязанные события и отправить их в одном конверте, чтобы уменьшить общее количество запросов.

Полный пакет имеет медиатип «application/vnd.docker.distribution.events.v1+json», который задается для запроса, поступающего на конечную точку.

Пример полного события может выглядеть следующим образом:

GET /callback HTTP/1.1
Host: application/vnd.docker.distribution.events.v1+json
Authorization: Bearer <your token, if needed>
Content-Type: application/vnd.docker.distribution.events.v1+json

{
  "events": [
    {
      "id": "asdf-asdf-asdf-asdf-0",
      "timestamp": "2006-01-02T15:04:05Z",
      "action": "push",
      "target": {
        "mediaType": "application/vnd.docker.distribution.manifest.v1+json",
        "length": 1,
        "digest": "sha256:fea8895f450959fa676bcc1df0611ea93823a735a01205fd8622846041d0c7cf",
        "repository": "library/test",
        "url": "https://example.com/v2/library/test/manifests/sha256:c3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5"
      },
      "request": {
        "id": "asdfasdf",
        "addr": "client.local",
        "host": "registrycluster.local",
        "method": "PUT",
        "useragent": "test/0.1"
      },
      "actor": {
        "name": "test-actor"
      },
      "source": {
        "addr": "hostname.local:port"
      }
    },
    {
      "id": "asdf-asdf-asdf-asdf-1",
      "timestamp": "2006-01-02T15:04:05Z",
      "action": "push",
      "target": {
        "mediaType": "application/vnd.docker.container.image.rootfs.diff+x-gtar",
        "length": 2,
        "digest": "sha256:c3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5",
        "repository": "library/test",
        "url": "https://example.com/v2/library/test/blobs/sha256:c3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5"
      },
      "request": {
        "id": "asdfasdf",
        "addr": "client.local",
        "host": "registrycluster.local",
        "method": "PUT",
        "useragent": "test/0.1"
      },
      "actor": {
        "name": "test-actor"
      },
      "source": {
        "addr": "hostname.local:port"
      }
    },
    {
      "id": "asdf-asdf-asdf-asdf-2",
      "timestamp": "2006-01-02T15:04:05Z",
      "action": "push",
      "target": {
        "mediaType": "application/vnd.docker.container.image.rootfs.diff+x-gtar",
        "length": 3,
        "digest": "sha256:c3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5",
        "repository": "library/test",
        "url": "https://example.com/v2/library/test/blobs/sha256:c3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5"
      },
      "request": {
        "id": "asdfasdf",
        "addr": "client.local",
        "host": "registrycluster.local",
        "method": "PUT",
        "useragent": "test/0.1"
      },
      "actor": {
        "name": "test-actor"
      },
      "source": {
        "addr": "hostname.local:port"
      }
    }
  ]
}

Ответы

Реестр справедливо принимает коды ответов от конечных точек. Если конечная точка отвечает любым кодом ответа 2xx или 3xx (после последующих перенаправлений), сообщение считается доставленным и отбрасывается.

В свою очередь рекомендуется, чтобы конечные точки также принимали входящие ответы. Хотя формат конвертов событий стандартизирован по типу носителя, любая «придирчивость» к проверке может привести к резервному копированию очереди в реестре.

Мониторинг

О состоянии конечных точек сообщается через http-интерфейс debug/vars, обычно настроенный на http://localhost:5001/debug/vars. Такая информация, как конфигурация и метрики, доступна по конечной точке.

Далее приведён пример нескольких конечных точек, которые испытали несколько сбоев и с тех пор были восстановлены:

{
  "notifications": {
    "endpoints": [
      {
        "name": "local-5003",
        "url": "http://localhost:5003/callback",
        "Headers": {
          "Authorization": [
            "Bearer \u003can example token\u003e"
          ]
        },
        "Timeout": 1000000000,
        "Threshold": 10,
        "Backoff": 1000000000,
        "Metrics": {
          "Pending": 76,
          "Events": 76,
          "Successes": 0,
          "Failures": 0,
          "Errors": 46,
          "Statuses": {
          }
        }
      },
      {
        "name": "local-8083",
        "url": "http://localhost:8083/callback",
        "Headers": null,
        "Timeout": 1000000000,
        "Threshold": 10,
        "Backoff": 1000000000,
        "Metrics": {
          "Pending": 0,
          "Events": 76,
          "Successes": 76,
          "Failures": 0,
          "Errors": 28,
          "Statuses": {
            "202 Accepted": 76
          }
        }
      }
    ]
  }
}

Если уведомление используется как часть более крупного приложения, важно отслеживать размер («Ожидание» выше) очередей конечных точек. Если сбои или размеры очередей увеличиваются, это может указывать на более серьезную проблему.

Журналы также являются ценным ресурсом для мониторинга проблем. Сбой конечной точки приводит к сообщениям, подобным следующим:

ERRO[0340] retryingsink: error writing events: httpSink{http://localhost:5003/callback}: error posting: Post http://localhost:5003/callback: dial tcp 127.0.0.1:5003: connection refused, retrying
WARN[0340] httpSink{http://localhost:5003/callback} encountered too many errors, backing off

Приведенное выше указывает на то, что несколько ошибок вызвали отсрочку, и реестр ожидает повторной попытки.

Соображения

В настоящее время очереди находятся в памяти, поэтому конечные точки должны быть достаточно надежными. Они предназначены для того, чтобы сделать все возможное для отправки сообщений, но если экземпляр потерян, сообщения могут быть удалены. Если конечная точка выходит из строя, следует позаботиться о том, чтобы экземпляр реестра не был остановлен до того, как конечная точка вернется в исходное состояние или сообщения будут потеряны.

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

Система уведомлений разработана на основе ряда взаимозаменяемых «приемников», которые можно подключить для достижения интересного поведения. Если эта система не обеспечивает приемлемых гарантий, возможно добавление транзакционного Sink в реестр, хотя это может повлиять на время обслуживания запроса. См. иди док для получения дополнительной информации.