如何处理docker API / images / create?

时间:2013-10-15 17:36:49

标签: docker

Docker API图像创建/拉动(/v1.6/images/create)显然总是返回

HTTP/1.1 200 OK
Content-Type: application/json

无论过程是成功还是失败。

此外,有效载荷无效json。

例如:/v1.6/images/create?fromImage = whatevertheflush

返回:

{"status":"Pulling repository whatevertheflush"}{"error":"Server error: 404 trying to fetch remote history for whatevertheflush","errorDetail":{"code":404,"message":"Server error: 404 trying to fetch remote history for whatevertheflush"}}

不是有效的json,并且没有转发/使用HTTP错误使得处理客户端错误变得很麻烦。

确实,docker-py只是呕吐有效载荷(https://github.com/dotcloud/docker-py/blob/master/docker/client.py#L374)。来自openstack的DockerHTTPClient尝试根据http错误代码返回一个值,该代码始终为200 ...(https://github.com/openstack/nova/blob/master/nova/virt/docker/client.py#L191

现在,我理解拉动可能需要很长时间,并且开始向客户端传输答案有点意义,但我不禁想到这里出了问题。

所以,这有三个方面:

  • 我在这里完全错过了什么?
  • 如果没有:如果您正在实现客户端应用程序(例如,在Python中),您将如何处理此问题(如果可能的话,优雅:) :)?尝试检测有效的json块,加载它们,并在我们“认为”出错的时候退出?
  • 如果没有:这将在未来的docker版本中改变(为了更好)吗?

3 个答案:

答案 0 :(得分:2)

这个问题有点老了,但是对于将来登陆此页面的未来读者,我想让您知道您并不孤单,我们会感到痛苦。这个API确实看起来很糟糕。

TL; DR回答为/images/create响应格式未记录;创建调用完成后,丢弃输出并查询/images/XXX/json。”

几年前,我编写了一些编排工具,但发现/images/create API非常烦人。但是,让我们开始吧:

  • 200响应中没有记录的架构; v1.19文档仅提供了一些记录的示例。 v1.37(在我撰写本文时是最新的)文档甚至没有走那么远,在所有响应中都没有提供详细信息。
  • 响应以Transfer-Encoding: chunked的形式发送,并且所发送的每条记录都以十六进制的字节数开头。这是一个低级摘录(绕过curl,所以我们可以看到实际发送的是什么):
    host-4:~ rg$ telnet localhost 2375
    Trying ::1...
    Connected to localhost.
    Escape character is '^]'.
    POST /images/create?fromImage=jenkins/jenkins:latest HTTP/1.1
    Host: localhost:2375
    User-Agent: foo/1.0
    Accept: */*

    HTTP/1.1 200 OK
    Api-Version: 1.39
    Content-Type: application/json
    Docker-Experimental: true
    Ostype: linux
    Server: Docker/18.09.1 (linux)
    Date: Wed, 06 Feb 2019 16:53:19 GMT
    Transfer-Encoding: chunked

    39
    {"status":"Pulling from jenkins/jenkins","id":"latest"}

    5e
    {"status":"Digest: sha256:abd3e3f96fbc3445c420fda590f37e2bd3377f69affd47b63b3d826d084c5ddc"}

    45
    {"status":"Status: Image is up to date for jenkins/jenkins:latest"}

    0
  • 是的,它可以传输图像下载进度-不提供对分块记录的低级别访问权限的客户端库可能只是在将数据提供给您之前对其进行了连接。如您所见,API的早期版本返回了JSON记录,唯一的分隔符是分块传输编码,因此客户端代码收到了一个未分隔JSON的串联块,必须通过跟踪curl / quotes / escape chars来解析它!此后已更新,现在可以发出以换行符分隔的记录,但是我们可以指望它们总是在那里吗?谁知道!此行为无需仪式即可更改,并且如果您在较新的守护程序上调用旧版本的API,则不会保留该行为。
  • 它立即返回200 OK,不代表成功或失败。 (鉴于调用的性质,我想它可能应该返回202 Accepted。理想情况下,我们会得到一个Location标头,指向可用于查询进度/状态。)
  • 返回的响应数据巨大,垃圾邮件,而且...很愚蠢。如果您有一个侦听TCP的docker实例,请尝试curl -Nv -X POST http://yourdocker:2375/images/create?fromImage=jenkins/jenkins:latest -o /tmp/omgwtf.txt。你会惊讶的。大量的带宽浪费在传输服务器渲染的ASCII条形图上!! 。实际上,记录以三种不同的方式返回每一层的进度,即当前和总字节的数字字段,条形图以及以MB或GB为单位的漂亮打印字符串。为什么这不只是呈现在客户端上?好问题。
    相反,您需要您的客户端解析千字节或兆字节的垃圾邮件。
  • 条形图具有>字符的随机转义的unicode rep,尽管它安全地位于JSON字符串中。有人只是在墙上扔逃生电话,看看有什么卡住了? ¯\ _(ツ)_ /¯
  • 记录本身是任意的。有一个id字段可以更改其引用的内容,而知道该记录的唯一方法就是解析人类可读的字符串。 Pulling from XXX vs Pulling fs layer vs Downloading等。据我所知,知道是否完成的唯一真实方法是跟踪所有id,并确保获得{{1 }},以关闭套接字。
  • 您也许可以寻找Pull complete,但是我不确定是否有多种可能的答案。
  • 就像我在开始时提到的那样,在Status: Downloaded newer image for XXX声称完成之后,您可能会很幸运地请求/images/XXX/json。这两个调用的结合将非常可靠地表明/images/create是否有效。

这是一个较长的串联客户端响应块,其中显示了一些不同的记录类型。为简洁起见,进行了编辑:

/images/create

此代码现在可以运行Internet。 = 8-O

答案 1 :(得分:0)

此特定端点实际上返回分块编码。卷曲的一个例子:

$ curl -v -X POST http://localhost:4243/images/create?fromImage=base
* About to connect() to localhost port 4243 (#0)
*   Trying ::1...
* Connection refused
*   Trying 127.0.0.1...
* connected
* Connected to localhost (127.0.0.1) port 4243 (#0)
> POST /images/create?fromImage=base HTTP/1.1
> User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8y zlib/1.2.5
> Host: localhost:4243
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Date: Fri, 07 Feb 2014 04:21:59 GMT
< Transfer-Encoding: chunked
<
* Connection #0 to host localhost left intact
{"status":"Pulling repository base"}{"status":"Pulling image (ubuntu-quantl) from      base","progressDetail":{},"id":"b750fe79269d"}{"status":"Pulling image (ubuntu-quantl) from base, endpoint: https://cdn-registry-1.docker.io/v1/","progressDetail":{},"id":"b750fe79269d"}{"status":"Pulling dependent layers","progressDetail":{},"id":"b750fe79269d"}{"status":"Download complete","progressDetail":{},"id":"27cf78414709"}{"status":"Download complete","progressDetail":{},"id":"b750fe79269d"}{"status":"Download complete","progressDetail":{},"id":"b750fe79269d"}* Closing connection #0

现在我不确定你是如何在Python中解析它的,但是在Ruby中,我可以这样使用Yajl

parts = []
Yajl::Parser.parse(body) { |o| parts << o }
puts parts
{"status"=>"Pulling repository base"}
{"status"=>"Pulling image (ubuntu-quantl) from base", "progressDetail"=>{}, "id"=>"b750fe79269d"}
{"status"=>"Pulling image (ubuntu-quantl) from base, endpoint: https://cdn-registry-1.docker.io/v1/", "progressDetail"=>{}, "id"=>"b750fe79269d"}
{"status"=>"Pulling dependent layers", "progressDetail"=>{}, "id"=>"b750fe79269d"}
{"status"=>"Download complete", "progressDetail"=>{}, "id"=>"27cf78414709"}
{"status"=>"Download complete", "progressDetail"=>{}, "id"=>"b750fe79269d"}
{"status"=>"Download complete", "progressDetail"=>{}, "id"=>"b750fe79269d"}

答案 2 :(得分:0)

使用Docker v1.9我还有这个问题需要处理。 在Docker Github存储库中也发现了一个问题:Docker uses invalid JSON format in some API functions #16925

某位参与者建议使用Content-Type HTTP标头,如下所示:application/json; boundary=NL 这不适合我。

然后,在使用我的自定义解析器时,发现了这个问题StackOverflow:How to handle a huge stream of JSON dictionaries?