Przypisywanie vhostów do portów Dockera

83

Mam skonfigurowany serwer DNS z symbolem wieloznacznym, tak aby wszystkie żądania internetowe kierowane do domeny niestandardowej (* .foo) były mapowane na adres IP hosta platformy Docker. Jeśli mam wiele kontenerów z instancjami Apache (lub Nginx), każdy kontener mapuje port Apache (80) na jakiś zewnętrzny port wejściowy.

To, co chciałbym zrobić, to wysłać żądanie do container-1.foo, który jest już zmapowany na poprawny adres IP (hosta Docker) za pośrednictwem mojego niestandardowego serwera DNS, ale przekazuję żądanie domyślnego portu 80 do odpowiedniego zewnętrznego Dockera port tak, aby właściwa instancja Apache z określonego kontenera była w stanie odpowiedzieć na podstawie domeny niestandardowej. Podobnie, container-2.foo będzie pośredniczył w proxy do apache drugiego kontenera i tak dalej.

Czy istnieje gotowe rozwiązanie do tego, najlepiej jest uruchomić proxy Nginx na hoście Docker, czy też powinienem napisać proxy node.js z potencjałem do zarządzania kontenerami Docker (uruchamianie / zatrzymywanie / przebudowywanie przez Internet ), czy ...? Jakie mam opcje, które sprawiłyby, że używanie kontenerów Dockera bardziej przypominałoby naturalne wydarzenie, a nie coś z obcymi portami i żonglowaniem kontenerami?

aranżer programu cyrkowego
źródło
Mam też to pytanie - o ile wiem, uruchomienie każdej aplikacji w kontenerze Dockera, a następnie wykonanie routingu na hoście za pomocą serwera nginx (być może w swoim własnym kontenerze) jest sposobem na to. Zastanawiam się, czy powinienem uruchomić serwer aplikacji samodzielnie (tj. Udostępnić serwer php-fpm, puma itp.), Czy też dołączyć (bezcelowe?) Wystąpienie nginx.
Ross
Spójrz na github.com/dotcloud/hipache , który jest odwrotnym proxy konfigurowanym przez redis.
ZeissS,

Odpowiedzi:

81

Ta odpowiedź może być nieco spóźniona, ale potrzebujesz automatycznego zwrotnego proxy. Użyłem do tego dwóch rozwiązań:

  • jwilder / nginx-proxy
  • Traefik

Z czasem wolę używać Traefika. Głównie dlatego, że jest dobrze udokumentowany i utrzymywany oraz zawiera więcej funkcji (równoważenie obciążenia z różnymi strategiami i priorytetami, kontrole stanu, wyłączniki automatyczne, automatyczne certyfikaty SSL z ACME / Let's Encrypt, ...).


Korzystanie z jwilder / nginx-proxy

Podczas uruchamiania kontenera Docker obraz Nginx-proxy Jason Wilder otrzymujesz serwer Nginx skonfigurowany jako odwrotne proxy dla innych kontenerów bez konfiguracji do obsługi.

Po prostu uruchom inne kontenery ze VIRTUAL_HOSTzmienną środowiskową, a nginx-proxy wykryje ich ip: port i zaktualizuje konfigurację nginx za Ciebie.

Powiedzmy, że Twój DNS jest skonfigurowany tak, że *.test.localmapuje na adres IP twojego hosta Dockera, a następnie uruchom następujące kontenery, aby uzyskać szybką demonstrację:

# 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

Korzystanie z Traefik

Podczas uruchamiania kontenera Traefik otrzymujesz konfigurację odwrotnego serwera proxy, który zrekonfiguruje swoje reguły przekierowania, biorąc pod uwagę etykiety Dockera znalezione na kontenerach.

Powiedzmy, że Twój DNS jest skonfigurowany tak, że *.test.localmapuje na adres IP twojego hosta Dockera, a następnie uruchom następujące kontenery, aby uzyskać szybką demonstrację:

# 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
źródło
-v /var/run/docker.sock:/tmp/docker.sockCzy to niebezpieczne rozwiązanie? Kontener to proxy Nginx ma dostęp do demona hosta docker? Czy to może być luka w zabezpieczeniach?
Mikl
możliwie. Należy również zauważyć, że brak udostępniania /var/run/docker.socknie jest gwarancją, że hosta dockera nie będzie można wykorzystać z kontenera. Bezpieczeństwo Dockera to temat sam w sobie.
Thomasleveil
Czy są jakieś znane problemy z bezpieczeństwem? Kiedy możesz połączyć się z hostem dockera z kontenera.
Mikl
Exploit istniał w przeszłości i problem został już rozwiązany, ale w przyszłości można znaleźć nowe. Docker nie polega na dodawaniu zabezpieczeń, chodzi o łatwość wdrażania
Thomasleveil
5
Możesz także oddzielnie uruchomić nginx-proxy i docker-gen, aby gniazdo Docker nie było zamontowane w kontenerze nginx.
Jason Wilder
42

Oto dwie możliwe odpowiedzi: (1) skonfiguruj porty bezpośrednio za pomocą Dockera i użyj Nginx / Apache do proxy dla vhostów lub (2) użyj Dokku do zarządzania portami i vhostami za ciebie (tak nauczyłem się robić metodę 1).

Metoda 1a (bezpośrednie przypisanie portów za pomocą platformy Docker)

Krok 1: Skonfiguruj nginx.conf lub Apache na hoście, ustawiając żądane numery portów. Ten serwer WWW, działający na hoście, będzie wykonywał proxy vhost. W przypadku Dockera nie ma w tym nic specjalnego - to normalny hosting vhost. Następnie, w kroku 2, pojawi się specjalna część, aby Docker używał prawidłowego numeru portu hosta.

Krok 2: Wymuś przypisanie numerów portów w Dockerze za pomocą „-p”, aby ustawić mapowania portów Dockera, i „-e”, aby ustawić niestandardowe zmienne środowiskowe w Dockerze, w następujący sposób:

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

Metoda 1b Zakodowany na stałe port aplikacji

... jeśli Twoja aplikacja korzysta z portu zakodowanego na stałe, na przykład portu 5000 (tj. nie można go skonfigurować za pomocą zmiennej środowiskowej PORT, jak w metodzie 1a), można ją zakodować na stałe za pomocą Dockera w następujący sposób:

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.

Metoda 2 (pozwól Dokku ustalić porty)

W tej chwili całkiem dobrą opcją do zarządzania vhostami Dockera jest Dokku . Nadchodzącą opcją może być użycie Flynna , ale w tej chwili Flynn dopiero się zaczyna i nie jest jeszcze gotowy. Dlatego na razie idziemy z Dokku: po wykonaniu instrukcji instalacji Dokku dla pojedynczej domeny włącz vhosty, tworząc plik „VHOST”:

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

Teraz, gdy aplikacja zostanie przesłana przez SSH do Dokku (zobacz dokumentację Dokku, aby dowiedzieć się, jak to zrobić), Dokku przejrzy plik VHOST i poda konkretną przekazaną aplikację (powiedzmy, że przekazałeś „container-1”), wygeneruje następujący plik:

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

Będzie miał następującą zawartość:

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;
  }
}

Po ponownym uruchomieniu serwera Dokku zapewni, że Docker uruchomi aplikację z portem mapowanym na pierwotnie wdrożony port (tutaj 49162), zamiast losowo przypisać inny port. Aby osiągnąć to deterministyczne przypisanie, Dokku zapisuje początkowo przypisany port do /home/git/container-1/PORTi przy następnym uruchomieniu ustawia PORTśrodowisko na tę wartość, a także mapuje przypisania portów Dockera tak, aby były tym portem zarówno po stronie hosta, jak i po stronie aplikacji. Jest to przeciwieństwo pierwszego uruchomienia, kiedy dokku ustawiPORT=5000 a następnie wymyśli dowolne losowe mapy portu Dokku po stronie VPS do 5000 po stronie aplikacji. Jest okrężna (i może się nawet zmienić w przyszłości), ale działa!

Sposób działania VHOST pod maską jest następujący: po wykonaniu git push aplikacji przez SSH, Dokku wykona haczyki, które żyją /var/lib/dokku/plugins/nginx-vhosts. Te haki są również znajduje się w kodzie źródłowym Dokku tutaj i są odpowiedzialne za pisanie nginx.confpliki z poprawnymi ustawieniami vhosta. Jeśli nie masz tego katalogu /var/lib/dokku, spróbuj uruchomić dokku plugins-install.

David Baird
źródło
3

Dzięki dockerowi chcesz, aby wewnętrzne adresy IP pozostały normalne (np. 80) i dowiedzieć się, jak połączyć losowe porty.

Jednym ze sposobów radzenia sobie z nimi jest odwrotne proxy, takie jak hipache. Skieruj na to swoje dns, a następnie możesz ponownie skonfigurować serwer proxy, gdy twoje kontenery będą się pojawiać i opadać. Zajrzyj na http://txt.fliglio.com/2013/09/protyping-web-stuff-with-docker/, aby zobaczyć, jak to może działać.

Jeśli szukasz czegoś solidniejszego, możesz rzucić okiem na „odkrywanie usług”. (spojrzenie na wykrywanie usług za pomocą docker: http://txt.fliglio.com/2013/12/service-discovery-with-docker-docker-links-and-beyond/ )

ben schwartz
źródło