我有一个在 docker 中运行的 GitLab 实例。GitLab 运行正常,但我无法访问GitLab 页面。
设置
概述
+------------+
Request+-->+ Cloudflare |
+-----+------+
|
v +---------+
Nginx+--->+Docker |
| +------+
| |GitLab|
+---------+
问题是 Nginx 无法将请求传递给 GitLab Pages 服务器(请注意,GitLab 本身可以工作)。
Nginx 错误日志条目
[error] 14932#14932: *30505 connect() failed (111: Connection refused) while connecting to upstream, [...]
Docker
image: gitlab/gitlab-ce
version: 13.7.1 (latest)
ip: 172.17.0.7 (dynamic)
published ports:
172.17.0.1:8080 -> 80
172.17.0.1:8090 -> 8090
Nginx
页面的服务器条目
server {
listen 80 default_server;
listen 443 default_server;
server_name _;
location / {
proxy_pass http://172.17.0.1:8090;
}
}
GitLab
grep -v '^#|^$' gitlab.rb1
nginx['listen_port'] = 80
nginx['listen_https'] = false
pages_external_url "http://pages.example.com/"
gitlab_pages['enable'] = true
gitlab_pages['external_http'] = []
gitlab_pages['listen_proxy'] = "localhost:8090"
gitlab_pages['inplace_chroot'] = true
gitlab_pages['metrics_address'] = ":9235"
pages_nginx['enable'] = true
pages_nginx['listen_https'] = false
pages_nginx['redirect_http_to_https'] = false
还尝试了绝对最小配置,仅定义pages_external_url
和gitlab_pages['enable']
。
追溯问题
- 来自 CF 的对 pages.example.com 的请求失败,错误代码为 502(网关错误)
- 检查Nginx日志,发现上面提到的日志条目
- 从主机向容器发出多个请求
# curl 172.17.0.1:8090 -> curl: (7) Failed to connect to 172.17.0.1 port 8090: Connection refused
# curl 172.17.0.7:8090 -> curl: (7) Failed to connect to 172.17.0.7 port 8090: Connection refused
- 向容器发出请求
# curl localhost:8090 -> 404 error page
由此我推测有什么东西阻塞了 8090 的传入流量(GitLab 页面),但请求 80(GitLab)已成功完成。我花了几天时间在 Google 上搜索这个问题,但没有找到任何东西。
1截断;SMTP、LDAP 和 omniauth 设置已删除
答案1
经过几个小时寻找错误的东西后,我终于找到了问题的原因(但稍后会详细介绍)。
总结
我必须更改gitlab_pages['listen_proxy']
每个接口上监听的值,因此它看起来像这样:
gitlab_pages['listen_proxy'] = "0.0.0.0:8090"
详细的
我使用与 gitlab pages 相关的关键字搜索了这个问题,现在我突然想到,也许我需要跳出思维定式,如果这是一个更普遍的问题,甚至与 GitLab Pages 无关,该怎么办。在第一次谷歌搜索后,我找到了一个好文章对这个。
我收到“连接被拒绝”消息,因为没有任何内容在端口 8090 上监听,因为localhost
指的是环回地址,即127.0.0.1
,但暴露的端口被转发到容器的 IP,在我的情况下是动态 IP,正如写问题时一样172.17.0.7
。因此,解决方案是监听每个可以使用0.0.0.0
IP 地址的接口。
两个直观展示问题和解决方案的图表
(图片取自上述文章,但略作修改以更好地匹配问题,并将其变为纯文本,以提高使用 force-darkmode 时的可读性)
使用时localhost:8090
:
Request +--------------------------------------+
+ | Default network namespace |
| | |
| | +-------+ |
v | +----->+ Nginx +------+ |
+-----+------+ | | +-------+ | |
| Cloudflare | | | | |
+-----+------+ | | v |
| +--------+-----------+-+-------+-------+
| | Physical interface | | Docker bridge |
+-------->+ 10.0.0.1 | | 172.17.0.1 |
+--------------------+ +-------+-------+
|
|
v
+-------+-------+
| Docker bridge |
| 172.17.0.7 |
+-------+-----------+-+---------------+
| | Loopback | |
| | 127.0.0.1 | |
| +-----+-----+ |
| | |
| | +--------------+ |
| +----->+ Pages server | |
| +--------------+ |
|GitLab's Network namespace |
+-------------------------------------+
监听每个接口,使用0.0.0.0:8090
:
Request +--------------------------------------+
+ | Default network namespace |
| | |
| | +-------+ |
v | +----->+ Nginx +------+ |
+-----+------+ | | +-------+ | |
| Cloudflare | | | | |
+-----+------+ | | v |
| +--------+-----------+-+-------+-------+
| | Physical interface | | Docker bridge |
+-------->+ 10.0.0.1 | | 172.17.0.1 |
+--------------------+ +-------+-------+
|
|
v
+-------+-------+
| Docker bridge |
| 172.17.0.7 |
+-------+-----------+-+-------+-------+
| | Loopback | | |
| | 127.0.0.1 | | |
| +-----+-----+ | |
| | v |
| | +--------+-----+ |
| +----->+ Pages server | |
| +--------------+ |
|GitLab's Network namespace |
+-------------------------------------+
答案2
我最新的 gitlab 16.xx 配置
GITLAB_OMNIBUS_CONFIG: |
### Web interace settings
external_url "https://gitlab.domain.org"
nginx['listen_port'] = 80
nginx['listen_https'] = false
### Pages
gitlab_pages['enable'] = true
pages_external_url "https://pages.domain.org"
pages_nginx['ssl'] = false
pages_nginx['listen_https'] = false
gitlab_pages['listen_proxy'] = '0.0.0.0:8090'
gitlab_pages['internal_gitlab_server'] = 'http://localhost:8080'
这是 1 个 docker 容器的配置,它位于反向代理(nginx/traefik/whatever)后面。如果您在负载均衡器上终止 https(TLS),它会将流量代理到 HTTP 端口:80 - gitlab,8090 - pages。