web-dev-qa-db-fra.com

conteneur nginx docker: 502 réponse de passerelle incorrecte

J'ai un service qui écoute le port 8080. Celui-ci n'est pas un conteneur.

Ensuite, j'ai créé un conteneur nginx en utilisant une image officielle:

docker run --name nginx -d -v /root/nginx/conf:/etc/nginx/conf.d -p 443:443 -p 80:80 nginx

Après tout:

# netstat -tupln | grep 443
tcp6       0      0 :::443                  :::*                    LISTEN      3482/docker-proxy
# netstat -tupln | grep 80
tcp6       0      0 :::80                   :::*                    LISTEN      3489/docker-proxy
tcp6       0      0 :::8080                 :::*                    LISTEN      1009/Java

La configuration de Nginx est:

upstream eighty {
    server 127.0.0.1:8080;
}

server {
    listen 80;
    server_name eighty.domain.com;

    location / {
      proxy_pass                        http://eighty;
    }
}

J'ai vérifié que je pouvais me connecter avec ce serveur avec # curl http://127.0.0.1:8080

 <html><head><meta http-equiv='refresh'
 content='1;url=/login?from=%2F'/><script>window.location.replace('/login?from=%2F');</script></head><body
 style='background-color:white; color:white;'>
 ...

Cela semble bien fonctionner, cependant, lorsque j'essaie d'accéder à l'aide de mon navigateur, nginx indique à bt une réponse de passerelle mauvaise.

Je suis en train de comprendre que cela peut être un problème lié à la visibilité entre une ouverture par un processus non conteneurisé et un conteneur. Est-ce que le conteneur peut établir une connexion avec un port ouvert par un processus autre que le conteneur?

MODIFIER

Journaux où upstream { server 127.0.0.1:8080; }:

2016/07/13 09:06:53 [error] 5#5: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 62.57.217.25, server: eighty.domain.com, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8080/", Host: "eighty.domain.com"
62.57.217.25 - - [13/Jul/2016:09:06:53 +0000] "GET / HTTP/1.1" 502 173 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0" "-"

Journaux où upstream { server 0.0.0.0:8080; }:

62.57.217.25 - - [13/Jul/2016:09:00:30 +0000] "GET / HTTP/1.1" 502 173 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0" "-" 2016/07/13 09:00:30 [error] 5#5: *1 connect() failed (111: Connection refused) while connecting to upstream, client:
62.57.217.25, server: eighty.domain.com, request: "GET / HTTP/1.1", upstream: "http://0.0.0.0:8080/", Host: "eighty.domain.com" 2016/07/13 09:00:32 [error] 5#5: *3 connect() failed (111: Connection refused) while connecting to upstream, client: 62.57.217.25, server: eighty.domain.com, request: "GET / HTTP/1.1", upstream: "http://0.0.0.0:8080/", Host: "eighty.domain.com"
62.57.217.25 - - [13/Jul/2016:09:00:32 +0000] "GET / HTTP/1.1" 502 173 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0" "-"

Des idées?

16
Jordi

Le problème

Localhost est un peu délicat quand il s'agit de conteneurs. Dans un conteneur docker, localhost pointe sur le conteneur lui-même . Cela signifie, avec un amont comme celui-ci:

upstream foo{
  server 127.0.0.1:8080;
}

ou 

upstream foo{
  server 0.0.0.0:8080;
}

vous dites à nginx de transmettre votre demande à l'hôte local . Mais dans le contexte d'un conteneur docker, localhost (et les adresses IP correspondantes) pointent vers le conteneur lui-même:

 enter image description here

en vous adressant à 127.0.0.1, vous n'atteindrez jamais votre ordinateur hôte si votre conteneur n'est pas sur le réseau hôte.

Solutions

Réseau hôte

Vous pouvez choisir d’exécuter nginx sur le même réseau que votre hôte:

docker run --name nginx -d -v /root/nginx/conf:/etc/nginx/conf.d --net=Host nginx

Notez qu'il n'est pas nécessaire d'exposer les ports dans ce cas.

Cela fonctionne bien que vous perdiez l’avantage du réseautage Docker Si plusieurs conteneurs doivent communiquer via le réseau Docker, cette approche peut poser problème. Si vous souhaitez simplement déployer nginx avec docker et ne pas utiliser de fonctionnalités réseau avancées, vous pouvez utiliser cette approche.

Accéder à l'adresse IP distante de l'hôte

Une autre approche consiste à reconfigurer votre directive nginx en amont pour vous connecter directement à votre ordinateur hôte en ajoutant son adresse IP distante:

upstream foo{
  //insert your hosts ip here
  server 192.168.99.100:8080;
}

Le conteneur va maintenant passer par la pile réseau et résoudre votre hôte correctement:

 enter image description here

Vous pouvez également utiliser votre nom DNS si vous en avez un. Assurez-vous que docker connaît votre serveur DNS.

31
ShrimpPhaser

Pour moi aidé cette ligne de code proxy_set_header Host $http_Host;

server {
   listen            80;
   server_name  localhost;
location / {
   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_set_header Host $http_Host;
   proxy_set_header X-NginX-Proxy true;

   proxy_redirect off;
   proxy_pass http://myserver;
}

nginx.sh

ip=$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | head -n 1)

docker run --name nginx --add-Host="Host:${ip}" -p 80:80 -d nginx

nginx.conf

location / {
    ...
    proxy_pass http://Host:8080/;
}

Ça marche pour moi

0
hehe Peng

Ce que vous pouvez faire est de configurer proxy_pass afin que, de la perspective container, l’adresse pointe vers votre hôte réel.

Pour obtenir une adresse Host du point de vue du conteneur, procédez comme suit sous Windows avec le code fixe 18.03 (ou plus récent):

Exécutez bash sur le conteneur de l'hôte où le nom de l'image est nginx (fonctionne sur Alpine Linux distribution):

 docker run -it nginx /bin/ash

Puis courez à l'intérieur du conteneur

/ # nslookup Host.docker.internal

Name:      Host.docker.internal
Address 1: 192.168.65.2

192.168.65.2 est l'adresse IP de l'hôte - pas l'adresse IP du pont comme dans spinus réponse acceptée.

J'utilise ici Host.docker.internal :

L'hôte a une adresse IP changeante (ou aucune si vous n'avez pas d'accès au réseau). À partir du 18.03, nous vous recommandons de vous connecter au nom DNS spécial Host.docker.internal, qui correspond à l'adresse IP interne utilisée par l'hôte. Ceci à des fins de développement et ne fonctionnera pas dans un environnement de production en dehors de Docker pour Windows.

Ensuite, vous pouvez changer la configuration nginx en: proxy_pass http://192.168.65.2:{your_app_port};

et ça devrait marcher. 

N'oubliez pas de fournir la même port que votre application locale s'exécute.

0
yami