web-dev-qa-db-fra.com

Docker Swarm obtient une véritable IP (hôte client) dans Nginx

J'ai une pile avec nginx et PHP pour fonctionner sur Docker Swarm Cluster.

Dans un instant dans mon PHP, j'ai besoin d'obtenir le remote_addr ($ _SERVER ['REMOTE_ADDR']) qui contient la véritable IP de l'hôte client accédant à ma webapp.

Mais le problème est que l'IP a informé pour nginx par cluster essaim docker. Il a montré une IP interne comme 10.255.0.2, mais la vraie IP est l'adresse IP externe de l'hôte client (comme 192.168.101.151).

Comment je peux résoudre ça?

Mon fichier docker-compose:

version: '3'

services:
  php:
    image: php:5.6
    volumes:
      - /var/www/:/var/www/
      - ./data/log/php:/var/log/php5
    networks:
      - backend
    deploy:
      replicas: 1
  web:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - /var/www/:/var/www/
      - ./data/log/nginx:/var/log/nginx
    networks:
      - backend
networks:
  backend:

Mon fichier default.conf (vhost.conf):

server {
    listen          80;
    root            /var/www;
    index           index.html index.htm index.php;

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

    location / {
        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;

        try_files   $uri $uri/ /index.php;
    }

    location = /50x.html {
        root   /var/www;
    }

    # set expiration of assets to MAX for caching
    location ~* \.(js|css|gif|png|jp?g|pdf|xml|oga|ogg|m4a|ogv|mp4|m4v|webm|svg|svgz|eot|ttf|otf|woff|ico|webp|appcache|manifest|htc|crx|oex|xpi|safariextz|vcf)(\?[0-9]+)?$ {
            expires max;
            log_not_found off;
    }

    location ~ \.php$ {
        try_files                   $uri =404;
        fastcgi_index               index.php;
        fastcgi_split_path_info     ^(.+\.php)(/.+)$;
        fastcgi_pass                php:9000;
        include                     fastcgi_params;
        fastcgi_param               SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param               PATH_INFO       $fastcgi_path_info;
        fastcgi_read_timeout        300;
    }
}

Mon fichier de configuration nginx:

user  nginx;
worker_processes    3;

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

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    keepalive_timeout   15;
    client_body_buffer_size     100K;
    client_header_buffer_size   1k;
    client_max_body_size        8m;
    large_client_header_buffers 2 1k;

    gzip             on;
    gzip_comp_level  2;
    gzip_min_length  1000;
    gzip_proxied     expired no-cache no-store private auth;
    gzip_types       text/plain application/x-javascript text/xml text/css application/xml;

    log_format  main  '$remote_addr - $remote_user [$time_local]  "$request_filename" "$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;

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

pour ceux qui ne veulent pas lire tout le fil github ( https://github.com/moby/moby/issues/25526 ), la réponse qui me convenait était de changer la configuration en ce :

version: '3.7'
services:
  nginx:
    ports:
      - mode: Host
        protocol: tcp
        published: 80
        target: 80
      - mode: Host
        protocol: tcp
        published: 443
        target: 81

Cela permet toujours au réseau de superposition interne de fonctionner, mais utilise certaines astuces avec iptables pour transférer ces ports directement vers le conteneur, de sorte que le service à l'intérieur du conteneur voit l'adresse IP source correcte des paquets.

Il n'y a aucune fonction dans iptables pour permettre l'équilibrage des ports entre plusieurs conteneurs, vous ne pouvez donc affecter qu'un seul port à un conteneur (qui inclut plusieurs répliques d'un conteneur).

5
Oreste Viron

Vous ne pouvez pas encore obtenir cela via un réseau de superposition. Si vous faites défiler de bas en haut sur ce problème de GitHub de longue date , vous verrez quelques options pour utiliser les réseaux de ponts dans Swarm avec vos mandataires pour contourner ce problème pour l'instant.

2
Bret Fisher

changer le mode de liaison de port en hôte a fonctionné pour moi

ports: 
  - mode: Host 
    protocol: tcp 
    published: 8082 
    target: 80

cependant, votre interface Web doit écouter sur un hôte spécifique à l'intérieur d'un cluster d'essaim, c'est-à-dire.

deploy: 
  placement: 
    constraints: 
      [node.role == manager]
2
Faraz Partoei