Odpowiedź @ T0xicCode jest prawidłowa, ale pomyślałem, że omówię szczegóły, ponieważ w końcu wdrożenie działającego rozwiązania zajęło mi około 20 godzin.
Jeśli chcesz uruchomić Nginx we własnym kontenerze i używać go jako odwrotnego serwera proxy do równoważenia obciążenia wielu aplikacji na tej samej instancji serwera, kroki, które musisz wykonać, są następujące:
Połącz swoje pojemniki
Kiedy używasz docker run
kontenerów, zazwyczaj wprowadzając do nich skrypt powłoki User Data
, możesz zadeklarować linki do innych działających kontenerów. Oznacza to, że musisz uruchomić swoje kontenery w odpowiedniej kolejności i tylko te ostatnie mogą łączyć się z pierwszymi. Tak jak to:
#!/bin/bash
sudo docker run -p 3000:3000 --name API mydockerhub/api
sudo docker run -p 3001:3001 --link API:API --name App mydockerhub/app
sudo docker run -p 80:80 -p 443:443 --link API:API --link App:App --name Nginx mydockerhub/nginx
Tak więc w tym przykładzie, API
pojemnik nie jest związana z żadnym innym, ale
App
pojemnik jest powiązana API
i Nginx
jest powiązana zarówno API
i App
.
Wynikiem tego są zmiany w env
zmiennych i /etc/hosts
plikach, które znajdują się w kontenerach API
i App
. Wyniki wyglądają tak:
/ etc / hosts
Uruchomienie cat /etc/hosts
w Twoim Nginx
kontenerze spowoduje:
172.17.0.5 0fd9a40ab5ec
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 App
172.17.0.2 API
ENV Vars
Uruchomienie env
w Twoim Nginx
kontenerze spowoduje:
API_PORT=tcp://172.17.0.2:3000
API_PORT_3000_TCP_PROTO=tcp
API_PORT_3000_TCP_PORT=3000
API_PORT_3000_TCP_ADDR=172.17.0.2
APP_PORT=tcp://172.17.0.3:3001
APP_PORT_3001_TCP_PROTO=tcp
APP_PORT_3001_TCP_PORT=3001
APP_PORT_3001_TCP_ADDR=172.17.0.3
Obcięłem wiele rzeczywistych zmiennych, ale powyższe są kluczowymi wartościami potrzebnymi do proxy ruchu do kontenerów.
Aby uzyskać powłokę do uruchamiania powyższych poleceń w działającym kontenerze, użyj następującego:
sudo docker exec -i -t Nginx bash
Możesz zobaczyć, że masz teraz zarówno /etc/hosts
wpisy w plikach, jak i env
zmienne, które zawierają lokalny adres IP dowolnego z połączonych kontenerów. O ile wiem, to wszystko, co dzieje się, gdy uruchamiasz kontenery z zadeklarowanymi opcjami linków. Ale teraz możesz użyć tych informacji do konfiguracji nginx
w swoim Nginx
kontenerze.
Konfigurowanie Nginx
To jest trochę trudne i jest kilka opcji. Możesz skonfigurować swoje witryny tak, aby wskazywały wpis w utworzonym /etc/hosts
pliku docker
, lub możesz użyć ENV
vars i uruchomić zamianę ciągu (użyłem sed
) na swoim nginx.conf
i wszelkich innych plikach conf, które mogą znajdować się w twoim /etc/nginx/sites-enabled
folderze, aby wstawić adres IP wartości.
OPCJA A: Skonfiguruj Nginx przy użyciu zmiennych ENV
Jest to opcja, z której skorzystałem, ponieważ nie mogłem uruchomić
/etc/hosts
opcji pliku. Wkrótce spróbuję Opcji B i zaktualizuję ten post o wszelkie ustalenia.
Kluczową różnicą między tą opcją a użyciem /etc/hosts
opcji file jest sposób, w jaki piszesz, Dockerfile
aby używał skryptu powłoki jako CMD
argumentu, który z kolei obsługuje zamianę ciągu w celu skopiowania wartości IP z ENV
do pliku (ów) conf.
Oto zestaw plików konfiguracyjnych, z którymi skończyłem:
Dockerfile
FROM ubuntu:14.04
MAINTAINER Your Name <you@myapp.com>
RUN apt-get update && apt-get install -y nano htop git nginx
ADD nginx.conf /etc/nginx/nginx.conf
ADD api.myapp.conf /etc/nginx/sites-enabled/api.myapp.conf
ADD app.myapp.conf /etc/nginx/sites-enabled/app.myapp.conf
ADD Nginx-Startup.sh /etc/nginx/Nginx-Startup.sh
EXPOSE 80 443
CMD ["/bin/bash","/etc/nginx/Nginx-Startup.sh"]
nginx.conf
daemon off;
user www-data;
pid /var/run/nginx.pid;
worker_processes 1;
events {
worker_connections 1024;
}
http {
# Basic Settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 33;
types_hash_max_size 2048;
server_tokens off;
server_names_hash_bucket_size 64;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging Settings
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# Gzip Settings
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 3;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/xml text/css application/x-javascript application/json;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
# Virtual Host Configs
include /etc/nginx/sites-enabled/*;
# Error Page Config
#error_page 403 404 500 502 /srv/Splash;
}
UWAGA: Ważne jest, aby to daemon off;
w nginx.conf
pliku, aby zapewnić, że pojemnik nie wyjść natychmiast po uruchomieniu.
api.myapp.conf
upstream api_upstream{
server APP_IP:3000;
}
server {
listen 80;
server_name api.myapp.com;
return 301 https://api.myapp.com/$request_uri;
}
server {
listen 443;
server_name api.myapp.com;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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;
proxy_cache_bypass $http_upgrade;
proxy_pass http://api_upstream;
}
}
Nginx-Startup.sh
#!/bin/bash
sed -i 's/APP_IP/'"$API_PORT_3000_TCP_ADDR"'/g' /etc/nginx/sites-enabled/api.myapp.com
sed -i 's/APP_IP/'"$APP_PORT_3001_TCP_ADDR"'/g' /etc/nginx/sites-enabled/app.myapp.com
service nginx start
Zostawię ci zadanie domowe z większością treści nginx.conf
i api.myapp.conf
.
Magia dzieje się wtedy, Nginx-Startup.sh
gdy używamy sed
do zamiany ciągu znaków w APP_IP
symbolu zastępczym, który zapisaliśmy w upstream
bloku naszych api.myapp.conf
i app.myapp.conf
plików.
To pytanie ask.ubuntu.com bardzo ładnie to wyjaśnia:
znajdź i zamień tekst w pliku za pomocą poleceń
GOTCHA
W OSX sed
inaczej obsługuje opcje, -i
szczególnie flaga. W Ubuntu -i
flaga obsłuży zastąpienie „na miejscu”; otworzy plik, zmieni tekst, a następnie „zapisze” ten sam plik. W systemie OSX -i
flaga wymaga rozszerzenia pliku, które ma mieć plik wynikowy. Jeśli pracujesz z plikiem, który nie ma rozszerzenia, musisz wprowadzić „” jako wartość -i
flagi.
GOTCHA
Aby użyć zmiennej ENV w wyrażeniu regularnym używanymsed
do znalezienia ciągu, który chcesz zastąpić, musisz umieścić zmienną w cudzysłowach. Tak więc poprawna, choć niewyraźnie wyglądająca, składnia jest taka, jak powyżej.
Dlatego docker uruchomił nasz kontener i uruchomił Nginx-Startup.sh
skrypt, który sed
zmienił wartość APP_IP
na odpowiednią ENV
zmienną, którą podaliśmy w sed
poleceniu. Mamy teraz pliki conf w naszym /etc/nginx/sites-enabled
katalogu, które mają adresy IP ze ENV
zmiennych ustawionych przez docker podczas uruchamiania kontenera. W api.myapp.conf
pliku zobaczysz, że upstream
blok zmienił się na ten:
upstream api_upstream{
server 172.0.0.2:3000;
}
Adres IP, który widzisz, może być inny, ale zauważyłem, że zwykle 172.0.0.x
.
Powinieneś teraz mieć wszystko poprawnie routowane.
GOTCHA
Po uruchomieniu pierwszego uruchomienia instancji nie można zrestartować / ponownie uruchomić żadnych kontenerów. Docker zapewnia każdemu kontenerowi nowy adres IP po uruchomieniu i nie wydaje się ponownie używać tego, który był wcześniej używany. Tak więc api.myapp.com
za pierwszym razem otrzyma 172.0.0.2, ale następnym razem otrzyma 172.0.0.4. Ale Nginx
już ustawił pierwszy adres IP w swoich plikach conf lub w swoim /etc/hosts
pliku, więc nie będzie w stanie określić nowego adresu IP dla api.myapp.com
. Rozwiązanie tego najprawdopodobniej będzie używane CoreOS
i jego etcd
usługa, która, w moim ograniczonym rozumieniu, działa jak wspólna ENV
dla wszystkich maszyn zarejestrowanych w tym samym CoreOS
klastrze. To kolejna zabawka, którą będę się bawił przy ustawianiu.
OPCJA B: Użyj /etc/hosts
wpisów pliku
To powinien być szybszy i łatwiejszy sposób na zrobienie tego, ale nie mogłem zmusić go do pracy. Pozornie po prostu wprowadzasz wartość /etc/hosts
wpisu do swoich plików api.myapp.conf
i app.myapp.conf
, ale nie mogłem uruchomić tej metody.
UPDATE:
Zobacz odpowiedź @Wes Tod, aby uzyskać instrukcje, jak sprawić, by ta metoda działała.
Oto próba, którą podjąłem api.myapp.conf
:
upstream api_upstream{
server API:3000;
}
Biorąc pod uwagę, że w moim /etc/hosts
pliku jest taki wpis: 172.0.0.2 API
pomyślałem, że po prostu ściągnie wartość, ale wygląda na to, że tak nie jest.
Miałem również kilka dodatkowych problemów z Elastic Load Balancer
pozyskiwaniem ze wszystkich AZ, więc mógł to być problem, gdy próbowałem tej trasy. Zamiast tego musiałem nauczyć się radzić sobie z zastępowaniem ciągów w Linuksie, więc to było zabawne. Spróbuję za chwilę i zobaczę, jak to działa.