草庐IT

docker - 如何处理 docker API/images/create?

coder 2023-05-27 原文

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 块,加载它们,并在我们“认为”有问题时退出?
  • 如果不是:这会在 future 的 docker 版本中改变(变得更好)吗?
  • 最佳答案

    这个问题有点老了,但对于登陆此页面的 future 读者,我想让你知道你并不孤单,我们感受到你的痛苦。这个 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 /引号/转义字符来解析它!它已经更新为现在发出由换行符分隔的记录,但我们可以指望它们一直存在吗?谁知道!这种行为无需任何仪式就改变了,如果您在较新的守护进程上调用旧版本的 API,则不会保留这种行为。
  • 立即返回200 OK,不代表成功或失败。 (考虑到调用的性质,我想它可能应该返回 202 Accepted。理想情况下,我们会得到一个 Location header ,指向一个我们可以用来查询进度/状态的新 URL。)
  • 返回的响应数据是巨大的、垃圾邮件,而且只是……愚蠢。如果您有一个 docker 实例监听 TCP,请尝试 curl -Nv -X POST http://yourdocker:2375/images/create?fromImage=jenkins/jenkins:latest -o /tmp/omgwtf.txt 。你会惊讶的。传输服务器渲染的 ASCII 条形图浪费了大量带宽!!!。事实上,记录以三种不同的方式返回每一层的进度,作为当前和总字节的数字字段,作为条形图,以及作为带有 MB 或 GB 单位的 pretty-print 字符串。为什么这不只是呈现在客户端?很好的问题。
    相反,您需要您的客户端解析千字节或兆字节的垃圾邮件。
  • 条形图有一个随机转义的 Unicode 代表 > 字符,尽管它安全地位于 JSON 字符串中。有人只是在墙上扔逃生电话,看看卡住了什么? ¯\_(ツ)_/¯
  • 记录本身非常随意。有一个 id 字段可以更改它引用的内容,这是了解解析人类可读字符串的记录类型的唯一方法。 Pulling from XXX vs Pulling fs layer vs Downloading 等等。据我所知,知道它是否完成的唯一真正方法是跟踪所有ID,并确保在套接字关闭时为每个ID获得Pull complete
  • 您也许可以查找 Status: Downloaded newer image for XXX,但我不确定是否有多种可能的响应。
  • 正如我在开头提到的,在 /images/XXX/json 声称完整之后,您可能会很幸运地请求 /images/create。这两个调用的组合将非常可靠地指示 /images/create 是否有效。

  • 这是一个较长的串联客户端响应块,显示了几种不同的记录类型。为简洁起见编辑:
    
        {"status":"Pulling from jenkins/jenkins","id":"latest"}
        {"status":"Pulling fs layer","progressDetail":{},"id":"ab1fc7e4bf91"}
        {"status":"Pulling fs layer","progressDetail":{},"id":"35fba333ff52"}
        {"status":"Pulling fs layer","progressDetail":{},"id":"f0cb1fa13079"}
        {"status":"Pulling fs layer","progressDetail":{},"id":"3d1dd648b5ad"}
        {"status":"Pulling fs layer","progressDetail":{},"id":"a9f886e483d6"}
        {"status":"Pulling fs layer","progressDetail":{},"id":"4346341d3c49"}
        ..
        "status":"Waiting","progressDetail":{},"id":"3d1dd648b5ad"}
        {"status":"Waiting","progressDetail":{},"id":"a9f886e483d6"}
        {"status":"Waiting","progressDetail":{},"id":"4346341d3c49"}
        {"status":"Waiting","progressDetail":{},"id":"006f2208d67a"}
        {"status":"Waiting","progressDetail":{},"id":"fb85cf26717d"}
        {"status":"Waiting","progressDetail":{},"id":"52ca068dbca7"}
        {"status":"Waiting","progressDetail":{},"id":"82f4759b8d12"}
        ...
        {"status":"Downloading","progressDetail":{"current":110118,"total":10780995},"progress":"[\u003e                                                  ]  110.1kB/10.78MB","id":"35fba333ff52"}
        {"status":"Downloading","progressDetail":{"current":457415,"total":45344749},"progress":"[\u003e                                                  ]  457.4kB/45.34MB","id":"ab1fc7e4bf91"}
        {"status":"Downloading","progressDetail":{"current":44427,"total":4340040},"progress":"[\u003e                                                  ]  44.43kB/4.34MB","id":"f0cb1fa13079"}
        {"status":"Downloading","progressDetail":{"current":817890,"total":10780995},"progress":"[===\u003e                                               ]  817.9kB/10.78MB","id":"35fba333ff52"}
        {"status":"Downloading","progressDetail":{"current":1833671,"total":45344749},"progress":"[==\u003e                                                ]  1.834MB/45.34MB","id":"ab1fc7e4bf91"}
        {"status":"Downloading","progressDetail":{"current":531179,"total":4340040},"progress":"[======\u003e                                            ]  531.2kB/4.34MB","id":"f0cb1fa13079"}
        {"status":"Downloading","progressDetail":{"current":1719010,"total":10780995},"progress":"[=======\u003e                                           ]  1.719MB/10.78MB","id":"35fba333ff52"}
        {"status":"Downloading","progressDetail":{"current":3205831,"total":45344749},"progress":"[===\u003e                                               ]  3.206MB/45.34MB","id":"ab1fc7e4bf91"}
        {"status":"Downloading","progressDetail":{"current":1129195,"total":4340040},"progress":"[=============\u003e                                     ]  1.129MB/4.34MB","id":"f0cb1fa13079"}
        {"status":"Downloading","progressDetail":{"current":2640610,"total":10780995},"progress":"[============\u003e                                      ]  2.641MB/10.78MB","id":"35fba333ff52"}
        {"status":"Downloading","progressDetail":{"current":1719019,"total":4340040},"progress":"[===================\u003e                               ]  1.719MB/4.34MB","id":"f0cb1fa13079"}
        {"status":"Downloading","progressDetail":{"current":4586183,"total":45344749},"progress":"[=====\u003e                                             ]  4.586MB/45.34MB","id":"ab1fc7e4bf91"}
        {"status":"Downloading","progressDetail":{"current":3549922,"total":10780995},"progress":"[================\u003e                                  ]   3.55MB/10.78MB","id":"35fba333ff52"}
        {"status":"Downloading","progressDetail":{"current":2513643,"total":4340040},"progress":"[============================\u003e                      ]  2.514M
        ...
        {"status":"Pull complete","progressDetail":{},"id":"6d9b49fc8a28"}
        {"status":"Extracting","progressDetail":{"current":380,"total":380},"progress":"[==================================================\u003e]     380B/380B","id":"6302e8b6563c"}
        {"status":"Extracting","progressDetail":{"current":380,"total":380},"progress":"[==================================================\u003e]     380B/380B","id":"6302e8b6563c"}
        {"status":"Pull complete","progressDetail":{},"id":"6302e8b6563c"}
        {"status":"Extracting","progressDetail":{"current":1548,"total":1548},"progress":"[==================================================\u003e]  1.548kB/1.548kB","id":"7348f018cf93"}
        {"status":"Extracting","progressDetail":{"current":1548,"total":1548},"progress":"[==================================================\u003e]  1.548kB/1.548kB","id":"7348f018cf93"}
        {"status":"Pull complete","progressDetail":{},"id":"7348f018cf93"}
        {"status":"Extracting","progressDetail":{"current":3083,"total":3083},"progress":"[==================================================\u003e]  3.083kB/3.083kB","id":"c651ee7bd59e"}
        {"status":"Extracting","progressDetail":{"current":3083,"total":3083},"progress":"[==================================================\u003e]  3.083kB/3.083kB","id":"c651ee7bd59e"}
        {"status":"Pull complete","progressDetail":{},"id":"c651ee7bd59e"}
        {"status":"Digest: sha256:abd3e3f96fbc3445c420fda590f37e2bd3377f69affd47b63b3d826d084c5ddc"}
        {"status":"Status: Downloaded newer image for jenkins/jenkins:latest"}
    
    

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

    关于docker - 如何处理 docker API/images/create?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19387501/

    有关docker - 如何处理 docker API/images/create?的更多相关文章

    1. ruby-on-rails - Enumerator.new 如何处理已通过的 block ? - 2

      我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m

    2. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

      1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

    3. ruby-on-rails - 如何处理 Grape 中特定操作的过滤器之前? - 2

      我正在我的Rails项目中安装Grape以构建RESTfulAPI。现在一些端点的操作需要身份验证,而另一些则不需要身份验证。例如,我有users端点,看起来像这样:moduleBackendmoduleV1classUsers现在如您所见,除了password/forget之外的所有操作都需要用户登录/验证。创建一个新的端点也没有意义,比如passwords并且只是删除password/forget从逻辑上讲,这个端点应该与用户资源。问题是Grapebefore过滤器没有像except,only这样的选项,我可以在其中说对某些操作应用过滤器。您通常如何干净利落地处理这种情况?

    4. ruby-on-rails - ActiveRecord 的 find_or_create* 方法是否存在根本性缺陷? - 2

      有几种方法:first_or_create_by、find_or_create_by等,它们的工作原理是:与数据库对话以尝试找到我们想要的东西如果我们找不到,就自己做保存到数据库显然,并发调用这些方法可能会使两个线程都找不到它们想要的东西,并且在第3步中一个线程会意外失败。似乎更好的解决方案是,创建或查找即:提前在您的数据库中创建合理的唯一性约束。如果你想保存一些东西,就保存它如果有效,那就太好了。如果它因为RecordNotUnique异常而无法工作,它已经存在,太好了,加载它那么在什么情况下我想使用Rails内置的东西而不是我自己的(看起来更可靠)create_or_find?

    5. Ruby - 如何处理子类意外覆盖父类(super class)私有(private)字段的问题? - 2

      假设您编写了一个类Sup,我决定将其扩展为SubSup。我不仅需要了解你发布的接口(interface),还需要了解你的私有(private)字段。见证这次失败:classSupdefinitialize@privateField="fromsup"enddefgetXreturn@privateFieldendendclassSub问题是,解决这个问题的正确方法是什么?看起来子类应该能够使用它想要的任何字段而不会弄乱父类(superclass)。编辑:equivalentexampleinJava返回"fromSup",这也是它应该产生的答案。 最佳答案

    6. ruby-on-rails - 工厂女孩/Rails : Generator to create a factory for existing model? - 2

      我在我的Rails项目中使用rspec_rails和factory_girl_railsgem。所有模型都已创建。是否有我可以运行的生成器来为现有模型创建工厂文件?例如:我已经有了一个Blog模型。RSpec允许我通过简单地运行以下命令在spec/models/blog_spec.rb生成一个模型规范文件:railsgeneraterspec:modelblog是否有我可以在命令行中运行的生成器,它会为这个现有模型生成工厂文件,位于:spec/factories/blogs.rb?我在factory_girl_rails中没有看到任何关于发电机的提及文档。

    7. ruby-on-rails - Rails - Carrierwave 进程抛出 ArgumentError : no images in this image list - 2

      在尝试实现应用auto_orient的过程之后!对于我的图片,我收到此错误:ArgumentError(noimagesinthisimagelist):app/uploaders/image_uploader.rb:36:in`fix_exif_rotation'app/controllers/posts_controller.rb:12:in`create'Carrierwave在没有进程的情况下工作正常,但在添加进程后尝试上传图像时抛出错误。流程如下:process:fix_exif_rotationdeffix_exif_rotationmanipulate!do|image|

    8. ruby-on-rails - rails : Find tasks that were created on a certain day? - 2

      我有一个任务列表(名称、starts_at),我试图在每日View中显示它们(就像iCal)。deftodays_tasks(day)Task.find(:all,:conditions=>["starts_atbetween?and?",day.beginning,day.ending]end我不知道如何将Time.now(例如“2009-04-1210:00:00”)动态转换为一天的开始(和结束),以便进行比较。 最佳答案 deftodays_tasks(now=Time.now)Task.find(:all,:conditio

    9. ruby-on-rails - 我如何处理 View 中的 nils? - 2

      我设置了以下模型:classContact:no_freq?validates_presence_of:freq,:if=>:no_band?protecteddefno_freq?freq.nil?enddefno_band?band.nil?endendclassBand当我在我的新View中输入频率时,如果输入了频率,则不允许指定波段。这在我的其他观点中造成了问题,因为band现在为零。我如何允许不指定band并在我的index和showView中显示为空,然后在editView中允许在以后指定一个。通过执行以下操作,我已经能够让我的索引显示空白:contact.band&&co

    10. ruby - 导轨 3 : Creating app with internal plugin system - 2

      我想在Rails中使用插件系统创建一个应用程序。潜在用户应该能够上传(或更好地从存储库安装)一个插件并安装它,使我的应用程序能够做更多的事情。这应该在没有FTP/SSH/对服务器的任何低级别访问的情况下完成。关于如何在Rails3中完成它,是否有任何好的gems或教程? 最佳答案 你看过http://edgeguides.rubyonrails.org/plugins.html了吗??它似乎不是100%兼容Rails3,但它可以帮助您入门。我看过的大多数插件文章都涉及Rails2。 关于

    随机推荐