Zuweisen von vhosts zu Docker-Ports

83

Ich habe ein Wildcard-DNS eingerichtet, damit alle Webanforderungen an eine benutzerdefinierte Domäne (* .foo) der IP-Adresse des Docker-Hosts zugeordnet werden. Wenn auf mehreren Containern Apache- (oder Nginx-) Instanzen ausgeführt werden, ordnet jeder Container den Apache-Port (80) einem externen eingehenden Port zu.

Ich möchte eine Anfrage an container-1.foo stellen, die bereits über meinen benutzerdefinierten DNS-Server der richtigen IP-Adresse (des Docker-Hosts) zugeordnet ist, aber die Standard-Port-80-Anfrage an den richtigen externen Docker weiterleiten Port so, dass die richtige Apache-Instanz aus dem angegebenen Container basierend auf der benutzerdefinierten Domäne antworten kann. Ebenso würde container-2.foo den Apache eines zweiten Containers vertreten und so weiter.

Gibt es eine vorgefertigte Lösung dafür, ist es meine beste Wahl, einen Nginx-Proxy auf dem Docker-Host auszuführen, oder sollte ich einen node.js-Proxy mit der Möglichkeit schreiben, Docker-Container zu verwalten (Start / Stopp / Neuaufbau über das Web) ), oder...? Welche Optionen habe ich, die die Verwendung der Docker-Container eher zu einem natürlichen Ereignis machen und nicht zu etwas mit fremden Ports und Container-Jonglieren?

Zirkusdirektor
quelle
Ich habe auch diese Frage - soweit ich das beurteilen kann, ist es der richtige Weg, jede App in einem Docker-Container auszuführen und dann das Routing auf dem Host mithilfe eines Nginx-Servers (möglicherweise in einem eigenen Container) durchzuführen. Ich frage mich, ob ich den App-Server eigenständig ausführen soll (dh einen PHP-Fpm-, Puma- usw. Server verfügbar machen) oder auch eine (sinnlose?) Nginx-Instanz einfügen soll.
Ross
Schauen Sie sich github.com/dotcloud/hipache an , einen Reverse-Proxy, der über redis konfiguriert werden kann.
ZeissS

Antworten:

81

Diese Antwort ist möglicherweise etwas spät, aber Sie benötigen einen automatischen Reverse-Proxy. Ich habe dafür zwei Lösungen verwendet:

  • jwilder / nginx-proxy
  • Traefik

Mit der Zeit bevorzuge ich Traefik. Vor allem, weil es gut dokumentiert und gewartet wird und über mehr Funktionen verfügt (Lastausgleich mit verschiedenen Strategien und Prioritäten, Integritätsprüfungen, Leistungsschalter, automatische SSL-Zertifikate mit ACME / Let's Encrypt, ...).


Verwenden von jwilder / nginx-proxy

Wenn Sie das Docker-Image eines Docker-Containers von Jason Wilder ausführen , wird ein Nginx-Server als Reverse-Proxy für Ihre anderen Container eingerichtet, für den keine Konfiguration erforderlich ist.

Führen Sie einfach Ihre anderen Container mit der VIRTUAL_HOSTUmgebungsvariablen aus, und nginx-proxy erkennt ihren ip: port und aktualisiert die nginx-Konfiguration für Sie.

Angenommen, Ihr DNS ist so eingerichtet, dass *.test.locales der IP-Adresse Ihres Docker-Hosts zugeordnet ist. Starten Sie dann einfach die folgenden Container, um eine schnelle Demo auszuführen:

# start the reverse proxy
docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock jwilder/nginx-proxy

# start a first container for http://tutum.test.local
docker run -d -e "VIRTUAL_HOST=tutum.test.local" tutum/hello-world

# start a second container for http://deis.test.local
docker run -d -e "VIRTUAL_HOST=deis.test.local" deis/helloworld

Traefik verwenden

Wenn Sie einen Traefik- Container ausführen , wird ein Reverse-Proxy-Server eingerichtet, der die Weiterleitungsregeln anhand der Docker-Labels auf Ihren Containern neu konfiguriert .

Angenommen, Ihr DNS ist so eingerichtet, dass *.test.locales der IP-Adresse Ihres Docker-Hosts zugeordnet ist. Starten Sie dann einfach die folgenden Container, um eine schnelle Demo auszuführen:

# start the reverse proxy
docker run --rm -it -p 80:80 -v /var/run/docker.sock:/var/run/docker.sock traefik:1.7 --docker

# start a first container for http://tutum.test.local
docker run -d -l "traefik.frontend.rule=Host:tutum.test.local" tutum/hello-world

# start a second container for http://deis.test.local
docker run -d -l "traefik.frontend.rule=Host:deis.test.local" deis/helloworld
Thomasleveil
quelle
-v /var/run/docker.sock:/tmp/docker.sockIst es eine gefährliche Lösung? Container dieser Nginx-Proxy hat Zugriff auf Docker-Host-Daemon? Kann dies eine mögliche Sicherheitslücke sein?
Mikl
möglicherweise. Beachten Sie auch, dass das Nicht-Teilen auch /var/run/docker.sockkeine Garantie dafür ist, dass der Docker-Host nicht aus einem Container ausgenutzt werden kann. Docker-Sicherheit ist ein Thema für sich.
Thomasleveil
Gibt es bekannte Sicherheitsprobleme? Wenn Sie den Docker-Host vom Container aus erreichen können.
Mikl
In der Vergangenheit gab es einen Exploit, und das Problem ist jetzt behoben, aber in Zukunft könnten neue Exploits gefunden werden. Bei Docker geht es nicht um zusätzliche Sicherheit, sondern um einfache Bereitstellung
Thomasleveil,
5
Sie können nginx-proxy und docker-gen auch separat ausführen, damit der Docker-Socket nicht auf dem nginx-Container bereitgestellt wird.
Jason Wilder
42

Hier sind zwei mögliche Antworten: (1) Richten Sie Ports direkt mit Docker ein und verwenden Sie Nginx / Apache, um die vhosts zu vertreten, oder (2) verwenden Sie Dokku , um Ports und vhosts für Sie zu verwalten (so habe ich gelernt, Methode 1 auszuführen).

Methode 1a (Ports direkt mit Docker zuweisen)

Schritt 1: Richten Sie nginx.conf oder Apache auf dem Host mit den gewünschten Portnummernzuweisungen ein. Dieser Webserver, der auf dem Host ausgeführt wird, übernimmt das vhost-Proxy. In Bezug auf Docker ist daran nichts Besonderes - es ist normales vhost-Hosting. Als nächstes kommt in Schritt 2 der spezielle Teil, damit Docker die richtige Host-Portnummer verwendet.

Schritt 2: Erzwingen Sie die Zuweisung von Portnummern in Docker mit "-p", um die Portzuordnungen von Docker festzulegen, und "-e", um benutzerdefinierte Umgebungsvariablen in Docker wie folgt festzulegen:

port=12345 # <-- the vhost port setting used in nginx/apache
IMAGE=myapps/container-1
id=$(docker run -d -p :$port -e PORT=$port $IMAGE)
# -p :$port will establish a mapping of 12345->12345 from outside docker to
# inside of docker.
# Then, the application must observe the PORT environment variable
# to launch itself on that port; This is set by -e PORT=$port.

# Additional goodies:
echo $id # <-- the running id of your container
echo $id > /app/files/CONTAINER # <-- remember Docker id for this instance
docker ps # <-- check that the app is running
docker logs $id # <-- look at the output of the running instance
docker kill $id # <-- to kill the app

Methode 1b Fest codierter Anwendungsport

... wenn Ihre Anwendung einen fest codierten Port verwendet, z. B. Port 5000 (dh kann nicht wie in Methode 1a über die PORT-Umgebungsvariable konfiguriert werden), kann er über Docker wie folgt fest codiert werden:

publicPort=12345
id=$(docker run -d -p $publicPort:5000 $IMAGE)
# -p $publicPort:5000 will map port 12345 outside of Docker to port 5000 inside
# of Docker. Therefore, nginx/apache must be configured to vhost proxy to 12345,
# and the application within Docker must be listening on 5000.

Methode 2 (lassen Sie Dokku die Ports herausfinden)

Im Moment ist Dokku eine ziemlich gute Option für die Verwaltung von Docker- Vhosts . Eine bevorstehende Option könnte die Verwendung von Flynn sein , aber ab sofort fängt Flynn gerade erst an und ist noch nicht ganz fertig. Deshalb entscheiden wir uns jetzt für Dokku: Nachdem Sie die Dokku-Installationsanweisungen für eine einzelne Domain befolgt haben, aktivieren Sie vhosts, indem Sie die Datei "VHOST" erstellen:

echo yourdomain.com > /home/git/VHOST
# in your case: echo foo > /home/git/VHOST

Wenn eine App über SSH an Dokku gesendet wird (Informationen hierzu finden Sie in den Dokku-Dokumenten), überprüft Dokku die VHOST-Datei und generiert sie für die jeweilige App (sagen wir, Sie haben "container-1" gedrückt) die folgende Datei:

/home/git/container-1/nginx.conf

Und es wird folgenden Inhalt haben:

upstream container-1 { server 127.0.0.1:49162; }
server {
  listen      80;
  server_name container-1.yourdomain.com;
  location    / {
    proxy_pass  http://container-1;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $remote_addr;
  }
}

Beim Neustart des Servers stellt Dokku sicher, dass Docker die Anwendung mit dem Port startet, der dem ursprünglich bereitgestellten Port zugeordnet ist (hier 49162), anstatt zufällig einen anderen Port zuzuweisen. Um diese deterministische Zuweisung zu erreichen, speichert Dokku den ursprünglich zugewiesenen Port in /home/git/container-1/PORTund setzt beim nächsten Start die PORTUmgebung auf diesen Wert und ordnet die Portzuweisungen von Docker sowohl auf der Host- als auch auf der App-Seite diesem Port zu. Dies steht im Gegensatz zum ersten Start, bei dem Dokku den PORT=5000zufälligen Port Dokku auf der VPS-Seite auf 5000 auf der App-Seite festlegt und dann herausfindet. Es ist rund (und könnte sich in Zukunft sogar ändern), aber es funktioniert!

Die Art und Weise, wie VHOST unter der Haube funktioniert, ist: Wenn Dokku einen Git-Push der App über SSH ausführt, führt er Hooks aus, in denen er lebt /var/lib/dokku/plugins/nginx-vhosts. Diese Haken sind auch in der Dokku Quellcode befindet sich hier und sind verantwortlich für das Schreiben der nginx.confDateien mit den korrekten Einstellungen vhost. Wenn Sie dieses Verzeichnis nicht haben /var/lib/dokku, versuchen Sie es auszuführen dokku plugins-install.

David Baird
quelle
3

Mit Docker möchten Sie, dass die internen IPs normal bleiben (z. B. 80) und herausfinden, wie die zufälligen Ports verkabelt werden.

Eine Möglichkeit, mit ihnen umzugehen, ist ein Reverse-Proxy wie Hipache. Zeigen Sie mit Ihrem DNS darauf, und konfigurieren Sie den Proxy neu, wenn Ihre Container auf und ab gehen. Schauen Sie unter http://txt.fliglio.com/2013/09/protyping-web-stuff-with-docker/ nach, wie dies funktionieren könnte.

Wenn Sie nach etwas Robusterem suchen, sollten Sie sich "Service Discovery" ansehen. (Ein Blick auf die Serviceerkennung mit Docker: http://txt.fliglio.com/2013/12/service-discovery-with-docker-docker-links-and-beyond/ )

ben schwartz
quelle