处理通知

预计阅读时间:10分钟

该页面包含有关使用开源Docker Registry托管自己的注册表的信息。有关Docker Hub的信息,它提供了托管注册表以及其他功能,例如团队,组织,Web挂钩,自动构建等,请参阅Docker Hub

注册表支持发送Webhook通知,以响应注册表中发生的事件。发送通知以响应清单推送和拉动以及分层推送和拉动。这些动作被序列化为事件。事件被排队到注册表内部的广播系统中,该系统将事件排队并将其分发到Endpoints

注册表通知的工作流程

终点

通知通过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,标题为“ Authorization:Bearer <您的令牌,如果需要的话>”。该请求将在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结构,并作为通知请求的主体发送。一个或多个事件以称为信封的结构发送。每个事件都有一个唯一的ID,可以根据需要唯一地标识传入的请求。除此之外,还提供了一个带有 target动作,用于标识事件期间发生突变的对象。

event下面描述了中可用的字段。

场地 类型 描述
ID 细绳 ID提供事件的唯一标识符。
时间戳记 时间 时间戳是事件发生的时间。
行动 细绳 动作指示什么动作包含所提供的事件。
目标 分布描述符 目标唯一地描述事件的目标。
长度 整型 内容的长度(以字节为单位)。与“描述符”中的“大小”字段相同。
资料库 细绳 存储库标识命名的存储库。
来自资源库 细绳 FromRepository标识从中装入Blob的命名存储库。
网址 细绳 URL提供了指向内容的直接链接。
标签 细绳 标签标识标签事件中的标签名称。
要求 请求记录 请求涵盖了生成事件的请求。
演员 ActorRecord Actor指定启动事件的代理。对于大多数情况,这可能来自请求的授权上下文。
来源 源记录 源标识生成事件的注册表节点。换句话说,当演员“发起”事件时,源“产生”事件。

以下是一个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"
      }
    }
  ]
}

删除清单和Blob时发送的事件的目标结构包含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响应代码响应(在重定向之后),则该消息被视为已传递,并被丢弃。

反过来,建议端点也接受传入的响应。尽管事件信封的格式通过媒体类型进行了标准化,但是有关验证的任何“挑剔”都可能导致队列在注册表上备份。

监控方式

端点的状态是通过debug / vars http接口(通常配置为)报告的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则可能向注册表中添加事务,尽管这可能会影响请求服务时间。有关 更多信息,请参见 godoc

注册表本地图像标签存储库分发通知高级