Docker

解决Nexus Docker仓库搜索镜像返回500错误

Jager · 2月16日 · 2019年 862次已读

之前用 Nexus 给团队搭建了一个数据仓库,其中 Docker 仓库配置教程已经整理分享到了博客《Nexus3 最佳实践系列:搭建 Docker 私有仓库》,但是一直有个小问题,使用 docker search 来搜索会返回 500 错误:

[root@localhost:~]# docker search idocker.io/hello-world
Error response from daemon: Unexpected status code 500

因为平常不怎么使用搜索,而且 Nexus 前台也有镜像浏览页面,所以一直没花时间去解决。年前封网好不容易有点空闲,寻思着解决下。

经过定位,发现了问题所在:Nexus 里面的 Docker 有 3 种类型仓库:group、hosted、proxy,也就是组合仓库、本地仓库和代理仓库,其中组合仓库就是本地仓库和代理仓库的聚合,通过测试发现只有本地仓库才支持 search 请求,其他 2 种类型仓库都会 500 错误。所以,报错的直接原因就是我将 search 的请求转发到了组合仓库导致的。

解决办法非常简单,在 nginx 转发里面加一条规则即可:

if ($request_uri ~ '/search') {
        set $upstream "nexus_docker_put"; 
 }

Ps:详见之前的文章:https://zhang.ge/5139.html 。

以下是定位过程,不感兴趣的可以忽略。。。

1、确认 Nginx 代理日志是正常打开状态,并 tail -f idocker.io.log 实时查看日志;

2、执行 docker search 发起搜索:

docker search idocker.io/hello-world

3、回过来查看日志:发现 500 错误的内容如下(我这边 Nginx 改成了 json 格式):

{
"client_ip": "192.168.1.100",
"http_host": "idocker.io",
"@timestamp": "2019-01-31T10:24:29+08:00",
"method": "GET",
"url": "/v1/search?q=hello-world&n=25",
"status": "500",
"http_referer": "-",
"body_bytes_sent": "1968",
"request_time": "2.372",
"http_user_agent": "docker/17.09.1-ce go/go1.8.3 git-commit/19e2cf6 kernel/3.10.107-1-tlinux2-0046 os/linux arch/amd64 UpstreamClient(Docker-Client/17.09.1-ce \\(linux\\))",
"total_bytes_sent": "2430",
"server_ip": "192.168.1.111"
}

2 个重要的信息:搜索请求使用的是 GET 方法,请求路径是 /v1/search?q=hello-world&n=25。

4、直接对仓库后端一次发起请求,首先试了下 group 组合仓库,端口 8082:

[root@localhost:~]# curl -k  "http://192.168.1.200:8082/v1/search?q=hello-world&n=25"

<!DOCTYPE html>
<html lang="en">
<head>
  <title>500 - Nexus Repository Manager</title>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>


  <!--[if lt IE 9]>
  <script>(new Image).src="/goto/aHR0cDovLzE5Mi4xNjguMS4yMDA6ODA4Mi9mYXZpY29uLmljbz8zLjE0LjAtMDQ=" target="_blank"</script>
  <![endif]-->
  <link rel="icon" type="image/png" href="/goto/aHR0cDovLzE5Mi4xNjguMS4yMDA6ODA4Mi9mYXZpY29uLTMyeDMyLnBuZz8zLjE0LjAtMDQ=" target="_blank" sizes="32x32">
  <link rel="mask-icon" href="/goto/aHR0cDovLzE5Mi4xNjguMS4yMDA6ODA4Mi9zYWZhcmktcGlubmVkLXRhYi5zdmc/My4xNC4wLTA0" target="_blank" color="#5bbad5">
  <link rel="icon" type="image/png" href="/goto/aHR0cDovLzE5Mi4xNjguMS4yMDA6ODA4Mi9mYXZpY29uLTE2eDE2LnBuZz8zLjE0LjAtMDQ=" target="_blank" sizes="16x16">
  <link rel="shortcut icon" href="/goto/aHR0cDovLzE5Mi4xNjguMS4yMDA6ODA4Mi9mYXZpY29uLmljbz8zLjE0LjAtMDQ=" target="_blank">
  <meta name="msapplication-TileImage" content="http://192.168.1.200:8082/mstile-144x144.png?3.14.0-04">
  <meta name="msapplication-TileColor" content="#00a300">

  <link rel="stylesheet" type="text/css" href="/goto/aHR0cDovLzE5Mi4xNjguMS4yMDA6ODA4Mi9zdGF0aWMvY3NzL25leHVzLWNvbnRlbnQuY3NzPzMuMTQuMC0wNA==" target="_blank"/>
</head>
<body>
<div class="nexus-header">
  <a href="/goto/aHR0cDovLzE5Mi4xNjguMS4yMDA6ODA4Mg==" target="_blank">
    <div class="product-logo">
      <img src="http://192.168.1.200:8082/static/images/nexus.png?3.14.0-04" alt="Product logo"/>
    </div>
    <div class="product-id">
      <div class="product-id__line-1">
        <span class="product-name">Nexus Repository Manager</span>
      </div>
      <div class="product-id__line-2">
        <span class="product-spec">OSS 3.14.0-04</span>
      </div>
    </div>
  </a>
</div>

<div class="nexus-body">
  <div class="content-header">
    <img src="http://192.168.1.200:8082/static/rapture/resources/icons/x32/exclamation.png?3.14.0-04" alt="Exclamation point" aria-role="presentation"/>
    <span class="title">Error 500</span>
    <span class="description">Internal Server Error</span>
  </div>
  <div class="content-body">
    <div class="content-section">
      javax.servlet.ServletException: java.lang.IllegalStateException: No case for assetKind: SEARCH
    </div>
      </div>
</div>
</body>
</html>

终于看到了关键的报错:

javax.servlet.ServletException: java.lang.IllegalStateException: No case for assetKind: SEARCH

大概意思是不支持 SEARCH,于是继续试了下 hosted 本地仓库,端口 8083:

[root@localhost:~]# curl -k  "http://192.168.1.200:8083/v1/search?q=hello-world&n=25"
{"query":"hello-world","num_results":3,"num_pages":1,"page":1,"page_size":25,"results":[{"star_count":0,"is_official":false,"name":"192.168.1.200:8083/hello-world-poncexu:latest","is_trusted":false,"is_automated":false,"description":null},{"star_count":0,"is_official":false,"name":"192.168.1.200:8083/hello-world:v1.0","is_trusted":false,"is_automated":false,"description":null},{"star_count":0,"is_official":false,"name":"192.168.1.200:8083/hello-world:v2.0","is_trusted":false,"is_automated":false,"description":null}]}

很明显是可以的,然后再试了下 proxy 代理仓库,都不行。因此确定只有本地仓库是可以搜索的!

回头看了下 Nginx 代理的配置,发现我之前将所有 GET 都丢给了组合仓库,也就是转发了拉取请求,将 PUT 丢给了本地仓库,意思是转发了推送请求。看来,还需要多加一个规则,将搜索请求转发到本地仓库。

也就是得出了上文的规则:

    # 设置默认使用推送代理
    set $upstream "nexus_docker_put";
    # 当请求是 GET,也就是拉取镜像的时候,这里改为拉取代理,如此便解决了拉取和推送的端口统一
    if ( $request_method ~* 'GET') {
        set $upstream "nexus_docker_get";
    }

    # !!! 本次新增的转发规则 !!!
    # 只有本地仓库才支持搜索,所以把搜索请求转到本地仓库
    if ($request_uri ~ '/search') {
        set $upstream "nexus_docker_put"; 
    }

这个规则明显要加到 PUT 转发规则之后,以覆盖之。

生效后,再次执行 docker search idocker.io/hello-world,结果如下:

[root@localhost:~]# docker search idocker.io/hello-world
NAME                                     DESCRIPTION          STARS      OFFICIAL     AUTOMATED
idocker.io/hello-world-jager:latest                             0                                
idocker.io/hello-world:v1.0                                     0                                
idocker.io/hello-world:v2.0                                     0

问题得到解决~!

当然,还有点遗憾的是代理和组合仓库不支持搜索~希望后续 Nexus 版本能够考虑加上这个特性。

11 条回应
  1. 励志语录 2019-2-16 · 21:48

    咦,第一次沙发,好紧张,有没有潜规则 :grin:

  2. 创业路上 2019-2-18 · 23:27

    不知道为什么,我的网站好像被百度鄙视了,权重一直是零,而且SEO数据一直不更新,郁闷啊

  3. 我爱技术网 2019-2-19 · 17:02

    跟着Jager大佬能学习到不少技术 :grin:

  4. i4t运维博客 2019-2-19 · 17:11

    请问一下博客,把整个网站都改成docker容器,性能会不会好一点? 我服务器是1h2g的

    • Koma 2019-4-14 · 11:02

      不会 甚至还有5%的损失

      • avatar
        Jager 2019-4-21 · 14:38

        5%就有点夸张了,基本可以忽略估计,而且一般像我们这种网站,这点损失感知不到,不像大站会千万倍的放大。

  5. wordpress建站吧 2019-2-24 · 9:00

    技术很niu 啊

  6. 跨境电商之家 2019-3-4 · 11:52

    感谢分享!!!

  7. 金稻田 2019-3-5 · 16:45

    很棒的教程 一直在找相关的内容 感谢分享

  8. 未来往事 2019-3-14 · 19:44

    很棒的教程 感谢分享

  9. 趣知识 2019-3-15 · 12:28

    Jager厉害啊,啥时搞了这么一名牛B的域名呀