Docker 中运行的 GitLab Pages 无法从容器外部访问

Docker 中运行的 GitLab Pages 无法从容器外部访问

我有一个在 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_urlgitlab_pages['enable']

追溯问题

  1. 来自 CF 的对 pages.example.com 的请求失败,错误代码为 502(网关错误)
  2. 检查Nginx日志,发现上面提到的日志条目
  3. 从主机向容器发出多个请求
    1. # curl 172.17.0.1:8090 -> curl: (7) Failed to connect to 172.17.0.1 port 8090: Connection refused
    2. # curl 172.17.0.7:8090 -> curl: (7) Failed to connect to 172.17.0.7 port 8090: Connection refused
  4. 向容器发出请求
    # 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.0IP 地址的接口。

两个直观展示问题和解决方案的图表

(图片取自上述文章,但略作修改以更好地匹配问题,并将其变为纯文本,以提高使用 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。

相关内容