之前用 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 版本能够考虑加上这个特性。



咦,第一次沙发,好紧张,有没有潜规则 :grin:
不知道为什么,我的网站好像被百度鄙视了,权重一直是零,而且SEO数据一直不更新,郁闷啊
跟着Jager大佬能学习到不少技术 :grin:
请问一下博客,把整个网站都改成docker容器,性能会不会好一点? 我服务器是1h2g的
不会 甚至还有5%的损失
5%就有点夸张了,基本可以忽略估计,而且一般像我们这种网站,这点损失感知不到,不像大站会千万倍的放大。
技术很niu 啊
感谢分享!!!
很棒的教程 一直在找相关的内容 感谢分享
很棒的教程 感谢分享
Jager厉害啊,啥时搞了这么一名牛B的域名呀