111:Docker 容器的 nginx 代理连接被拒绝

111:Docker 容器的 nginx 代理连接被拒绝
  • CentOS 7

我有一个简单的 Nginx 代理 Docker 容器,监听端口 80。以下是 Dockerfile:

FROM centos:7
MAINTAINER Brian Ogden

# Not currently being used but may come in handy
ARG ENVIRONMENT

RUN yum -y update && \
    yum clean all && \
    yum -y install http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm \
    yum -y makecache && \
    yum -y install nginx-1.12.0 wget

# Cleanup some default NGINX configuration files we don’t need
RUN rm -f /etc/nginx/conf.d/default.conf


COPY /conf/proxy.conf /etc/nginx/conf.d/proxy.conf
COPY /conf/nginx.conf /etc/nginx/nginx.conf


CMD ["nginx"]

对于这个 Nginx 代理,这是我的 nginx.conf:

daemon off;
user  nginx;
worker_processes  2;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
    use epoll;
    accept_mutex off;
}


http {
    include       /etc/nginx/mime.types;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    client_max_body_size 300m;
    client_body_buffer_size 300k;
    large_client_header_buffers 8 64k;

    gzip  on;
    gzip_http_version 1.0;
    gzip_comp_level 6;
    gzip_min_length 0;
    gzip_buffers 16 8k;
    gzip_proxied any;
    gzip_types text/plain text/css text/xml text/javascript application/xml application/xml+rss application/javascript application/json;
    gzip_disable "MSIE [1-6]\.";
    gzip_vary on;

    include /etc/nginx/conf.d/*.conf;
}

这是我的代理配置:

upstream accountstaging {
    server 127.0.0.1:5023;
}

server {

    listen 80;
    server_name account.staging.mysite.com;

    location / {
        proxy_pass         http://accountstaging;
        proxy_redirect     off;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Host $server_name;
    }
}

我的代理配置正在监听端口 80,并尝试从 account.staging.mysite.com 向与监听端口 5023 的 Ngnix 代理在同一 Docker 主机上运行的 Docker 容器发出请求。

这是我的 Nginx 代理的 docker-compose.yml:

version: '3'
services:
  reverseproxy:
    build: 
      context: ./
      dockerfile: docker/Dockerfile
    image: tsl.devops.reverseproxy.image
    container_name: tsl.devops.reverseproxy.container
    ports:
      - "80:80"

这是监听端口 5023 的 Docker 容器的 docker-compose.yml:版本:'3'

services:
  apistaging:
    build: 
      context: ./
      dockerfile: docker/staging/Dockerfile
    image: tsl.api.example.image
    container_name: tsl.api.example.container
    ports:
      - "127.0.0.1:5023:80"

Dockerfile 对于我的问题来说实际上并不重要,但无论如何它在这里:

FROM tsl.devops.dotnetcore.base.image:2
MAINTAINER Brian Ogden

WORKDIR /app
COPY ./src/Tsl.Example/bin/Release/netcoreapp2.0/publish .

ENTRYPOINT ["dotnet", "Tsl.Example.dll"]

我跟着这个例子设置我的代理。

我之前在 Stackexchange 论坛上问过一个相关问题这里这里。这个问题我已经改进并简化了场景,将其简化为一个简单的代理,将请求转发到一个监听端口 5023 的 Docker 容器。

由于我的基础镜像是 CentOS,因此我遵循这里确保 SELinux 允许转发到端口 5023

答案1

得益于此这里有问答,我意识到我有两个问题:

  1. 由于我使用了两个不同的 docker-compose.yml 文件,因此这些容器具有不同的默认 Docker 网络,我曾设想我的 Ngnix 代理完全独立于我的任何 API 容器(包括 docker-compose)工作,有关该问题的更多信息请参见下文
  2. 第二个问题很简单,当我尝试代理到 127.0.0.1:5023 时,这是 Ngnix 容器内的本地主机,而不是 Nginx 代理容器外部的网络

因此,docker-compose 为我的 Nginx 代理 docker 容器和我的 api docker 容器创建不同的默认网络是因为我使用了两个不同的 docker-compose.yml 文件。这是因为我为许多 API 微服务构建了 Jenkins,因此它们具有独立的 docker-compose 文件,并且我需要一个 Nginx 代理将端口 80 上的请求转发到每个微服务。

为了测试这一点,为两个容器、API 和 Nginx 代理创建了一个 docker-compose.yml:

version: '3'

services:
  reverseproxy:
    build: 
      context: ./
      dockerfile: docker/nginxproxy/docker/Dockerfile
    image: tsl.devops.reverseproxy.image
    container_name: tsl.devops.reverseproxy.container
    ports:
      - "80:80"
  apistaging:
    build: 
      context: ./
      dockerfile: docker/staging/Dockerfile
    image: tsl.api.example.image
    container_name: tsl.api.example.container
    ports:
      - "5023:5023"
    environment: 
      ASPNETCORE_URLS: http://+:5023

是的,仍然存在一个问题,代理传递给 http//:127.0.0.1:5023,该转发保留在 Nginx Docker 容器中,并且永远找不到在 Docker 主机上运行的 API,我只需要使用 docker-compose.yml 服务名称来获取它:

upstream accountstaging {
    server apistaging:5023;
}

server {

    listen 80;
    server_name account.staging.mysite.com;

    location / {
        proxy_pass         http://accountstaging;
        proxy_redirect     off;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Host $server_name;
    }
}

答案2

我遇到了这个问题,但我的问题是,我有两个文件夹,它们都包含 docker-compose.yml 文件,而这两个文件都包含一个名为“web”的服务。我更改了其中一个服务的名称。

为了帮助那些像我一样在 Docker 网络方面苦苦挣扎的人,以下是完整的图片:

Docker-compose 项目经常使用 nginx 作为反向代理将 http 流量路由到其他 docker 服务。nginx 是我的一个服务,projectfolder/docker-compose.yml它连接到两个 docker 网络。

一个是我使用 docker-compose up 时创建的默认网络projectfolder/docker-compose.yml(它已命名projectfolder_default并且服务默认连接到它,除非您networks的服务具有另一个网络的属性,然后请确保将其添加- default到列表中)。当我运行时,docker network ls我看到了projectfolder_default列表,当我运行时,docker network inspect projectfolder_default我看到了 nginx 容器,所以一切都很好。

另一个是my_custom_network我自己建立的网络。我有一个启动脚本,如果网络不存在,它会创建它,方法是使用https://stackoverflow.com/a/53052379/13815107web我需要它来与中的服务进行通信otherproject/docker-compose.yml。我已正确添加my_custom_network到:

  • nginx服务的网络列表projectfolder/docker-compose.yml
  • 底部projectfolder/docker-compose.yml
  • web服务网络otherproject/docker-compose.yml
  • 底部otherproject/docker-compose.yml

网络出现并且有正确的容器使用docker network lsdocker network inspect my_custom_network

但是,我以为调用 http://web 会映射到 docker 服务web.projectfolder_default。我错了。我在 nginx 容器上打开了 shell ( docker exec -it nginx sh)。当我使用ping web(可能需要apt-get update, apt-get install iputils-ping)时,它成功了,但它打印了一个 url,my_custom_network这就是我找出错误的方法。

项目文件夹/docker-compose.yml

  services:
    # http://web did NOT map to this service!! Use http://web.main_default or change the names
    web:
      ... 
    nginx:
        ...
      links:
        - web
      networks:
        - default
        - my_custom_network
    ...
  networks:
    - my_custom_network
      external: true

其他项目/docker-compose.yml

  services:
    # http://web connected to this service instead. You could use http://web.my_custom_network to call it out instead
    web:
      ... 
      networks:
        - default
        - my_custom_network
    ...
  networks:
    - my_custom_network
      external: true

projectfolder/.../nginx/server.conf.template (Dockerfile 旁边)...

server {

    ...

    location /auth {
        internal;
        # This routed to wrong 'web'
        proxy_pass              http://web:9001;
        proxy_pass_request_body off;
        proxy_set_header        Content-Length "";
    }

    location / {
        alias /data/dist/;
    }

    location /robots.txt {
        alias /robots.txt;
    }

    # Project Folder backend
    location ~ ^/(api|login|logout)/ {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_connect_timeout 300s;
        proxy_read_timeout 300s;
        # This routed to wrong 'web'
        proxy_pass http://web:9001;
    }

    # Other project UI
    location /other-project {
        alias /data/other-project-client/dist/;
    }

    # Other project Django server
    location ~ ^/other-project/(rest)/ {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_connect_timeout 300s;
        proxy_read_timeout 300s;
        # This should work
        proxy_pass http://web.my_custom_network:8000;
    }
}

相关内容