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;
}
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).
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.
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]