Miliony użytkowników korzystają z Internetu, aby uzyskiwać dostęp do informacji w różnych celach, w tym do nauki, rozrywki, wiadomości i dzielenia się postępami w swoim życiu’ z przyjaciółmi. Dlatego podczas wdrażania aplikacji w Twoim najlepszym interesie jest wdrożenie wysoce bezpiecznej i skalowalnej infrastruktury dla Twojej aplikacji. Chmura oferuje różne sposoby zabezpieczania i skalowania Django aplikacji. Skalowanie poziome to jedna z metod, która pozwala na uruchomienie kilku kopii aplikacji. Zapewnia to większą odporność na awarie i wysoką dostępność. Zwiększa to również jej wydajność w zakresie jednoczesnego przetwarzania wielu żądań.
Poziome skalowanie aplikacji Django
Możesz skalować poziomo aplikację Django, udostępniając kilka serwerów aplikacji, na których działa aplikacja Django i jej serwer HTTP WSGI (taki jak Gunicorn lub uWSGI). Następnie konieczne będzie skonfigurowanie infrastruktury do dystrybucji przychodzących żądań pomiędzy te serwery aplikacji. Moduł równoważenia obciążenia oraz odwrócone proxy, takie jak Nginx, mogą pomóc Twojej infrastrukturze w dystrybucji ruchu. Nginx może wdrożyć certyfikaty SSL zapewniając bezpieczne połączenia z Twoją aplikacją za pośrednictwem protokołu HTTPS. Na koniec, Nginx może również zapewniać buforowanie zawartości statycznej, aby zminimalizować obciążenie serwera.
Konfigurowanie tych różnych komponentów osobno i zapewnienie ich komunikacji może być trudnym zadaniem. Na szczęście użycie Docker upraszcza proces konfiguracji i zapewnia, że poszczególne komponenty zachowują się w ten sam sposób, niezależnie od miejsca ich wdrożenia.
Co będziesz robić w tym poradniku
W tym poradniku dowiesz się, jak poziomo skalować skonteneryzowaną aplikację Django, obsługiwaną przez serwer HTTP WSGI Gunicorn. Udostępnisz dwa serwery aplikacji, każdy z zainstalowanym Dockerem, na których będzie działać ta sama kopia kontenera aplikacji Django i Gunicorn.
Zabezpieczysz również swoją aplikację za pomocą Let’s Encrypt certyfikatu SSL poprzez udostępnienie i skonfigurowanie trzeciego serwera proxy, na którym będzie działać kontener odwróconego proxy Nginx oraz kontener klienta Certbot. Certbot to pakiet, który pomaga w zarządzaniu certyfikatami SSL z urzędu certyfikacji Let’s Encrypt. Pobiera on certyfikat, konfiguruje bloki serwera Nginx z lokalizacją certyfikatu i zarządza automatycznym odnawianiem. Robi to poprzez skonfigurowanie zadania cron, które okresowo sprawdza, czy certyfikat wkrótce wygaśnie i wymaga odnowienia. Dzięki regularnemu aktualizowaniu certyfikatu SSL Twoja witryna zawsze będzie miała wysoką ocenę bezpieczeństwa w serwisie SSL Labs.
Ten trzeci serwer proxy znajduje się przed Twoją rozproszoną architekturą i odbiera cały przychodzący ruch zewnętrzny. Następnie dystrybuuje ten ruch do serwerów aplikacji. Serwery aplikacji znajdują się za zaporą sieciową, która zezwala na dostęp do nich wyłącznie serwerowi proxy.
Ten samouczek jest drugim z serii trzech samouczków dotyczących pracy z Django, Dockerem i Kubernetesem. W pierwszej kolejności należy wykonać kroki opisane w samouczku dotyczącym Budowania aplikacji Django i Gunicorn za pomocą Dockera na systemie Ubuntu. W tamtym samouczku skonfigurowaliśmy bazowy kod projektu, plik Dockerfile i połączyliśmy aplikację z usługą MinIo Simple Storage Service (S3) w celu serwowania naszych plików statycznych.
Wymagania wstępne
Aby móc postępować zgodnie z tym samouczkiem, będziesz potrzebować:
- Czterech serwerów Ubuntu 20.04:
Jeśli wykonałeś kroki opisane w samouczku będącym wymaganiem wstępnym, Budowanie aplikacji Django i Gunicorn za pomocą Dockera na systemie Ubuntu, masz już dwa z czterech serwerów:
-
Na pierwszym serwerze będzie działać instancja bazy danych PostgreSQL. Wykonaj kroki 1 i 2 z samouczka: Budowanie aplikacji Django i Gunicorn za pomocą Dockera na systemie Ubuntu, aby skonfigurować bazę danych. Konfiguracja Postgres powinna zostać zmodyfikowana tak, aby zezwalać na połączenia zewnętrzne wyłącznie z adresów IP Twoich serwerów aplikacji.
-
Na drugim i trzecim serwerze będą hostowane kontenery z kodem Twojej aplikacji. Powinieneś już mieć uruchomiony drugi serwer z samouczka będącego wymaganiem wstępnym. Będziemy modyfikować jego zaporę sieciową, aby zezwalała na połączenia zewnętrzne wyłącznie z adresu IP serwera proxy. Możesz wykonać kroki od 1 do 4 z tego samouczka krok po kroku, który pomoże Ci skonfigurować serwer Ubuntu na CloudSigma.
-
Ten czwarty serwer będzie serwerem proxy obsługującym równoważenie obciążenia i dystrybucję ruchu do dwóch kontenerów serwerów aplikacji.
-
Docker powinien być zainstalowany na dwóch serwerach aplikacji i serwerze proxy.
Po wykonaniu kroków opisanych w samouczku wstępnym, powinieneś mieć już zainstalowanego Dockera na jednym z serwerów. Możesz postępować zgodnie z krokami 1, 2 i 3 naszego samouczka dotyczącego instalacji i obsługi Dockera. Pamiętaj, aby dodać utworzonego powyżej użytkownika sudo do grupy Docker.
- Zarejestruj nazwę domeny i skonfiguruj jej rekordy DNS tak, aby wskazywały na publiczny adres IP serwera proxy. Do celów demonstracyjnych użyjemy example_domain.com.
-
Skonfiguruj usługę przechowywania obiektów S3. Jako usługi przechowywania w samouczku wstępnym użyliśmy MinIO jako usługi przechowywania. W związku z tym postępuj zgodnie z wyjaśnieniami w Kroku 5 of the samouczka wstępnego w celu skonfigurowania swojego MinIO bucketu pamięci masowej.
Krok 1: Weryfikacja działania pierwszego serwera aplikacji Django
Jak wyjaśniono w sekcji Wymagania wstępne, ten przewodnik następuje po samouczku dotyczącym Budowania aplikacji Django i Gunicorn z Dockerem na Ubuntu. Jeśli trafiłeś tu z tamtego samouczka i wykonałeś już opisane kroki, powinieneś mieć uruchomiony pierwszy serwer. Kod aplikacji opiera się na samouczku z dokumentacji Django dotyczącym aplikacji Polls. Ważne jest, aby zapoznać się z tymi krokami, aby zrozumieć wstępną konfigurację. Jeśli wykonałeś kroki opisane w samouczku, możesz pominąć ten pierwszy krok.
W przeciwnym razie możesz po prostu sklonować zdokeryzowaną gałąź na swój serwer. Zacznij od zalogowania się na swój pierwszy serwer aplikacji i wykonaj następujące polecenie git w celu sklonowania gałęzi django-polls-docker repozytorium django-polls:
|
1 |
git clone --single-branch --branch django-polls-docker --depth 1 https://github.com/jaymoh/django-polls.git |
Następnie przejdź do katalogu django-polls:
cd django-polls
W tym katalogu znajdziesz plik Dockerfile używany przez Dockera do budowania obrazu aplikacji, katalog django-polls zawierający kod aplikacji w języku Python oraz plik env zawierający listę zmiennych środowiskowych, które zostaną przekane do kontenera przy uruchomieniu w celu zmodyfikowania jego zachowania. W pliku Dockerfile, definiujemy zależności pakietów Django poprzez plik requirements.txt. Ponadto musimy zadeklarować port 8000 do przyjmowania ruchu przychodzącego i ustawić go na uruchamianie serwera gunicorn z 3 procesami roboczymi. Aby dowiedzieć się więcej o instrukcjach Dockerfile, zapoznaj się z Krokiem 7 samouczka Budowanie aplikacji Django i Gunicorn z Dockerem na Ubuntu.
Możesz zbudować obraz Dockera za pomocą polecenia:
docker build -t django-polls:v1 .
Po zbudowaniu obrazu przez Dockera możesz wyświetlić listę dostępnych obrazów na serwerze za pomocą następującego polecenia:
docker images
Oto dane wyjściowe po uruchomieniu polecenia:
Następnie musimy zmodyfikować plik env używany do konfiguracji środowiska uruchomieniowego. Plik ten jest przekazywany do kontenera Docker podczas jego uruchamiania. Otwórz plik env za pomocą edytora nano:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
DJANGO_SECRET_KEY=your_secret_key DEBUG= DJANGO_LOGLEVEL=info DJANGO_ALLOWED_HOSTS=your_server_IP_address DB_ENGINE=postgresql_psycopg2 DB_DATABASE=polls_db DB_USERNAME=hackins DB_PASSWORD=your_database_password DB_HOST=your_database_host DB_PORT=your_database_port STATIC_DEFAULT_FILE_STORAGE=storages.backends.s3boto3.S3Boto3Storage STATIC_MINIO_BUCKET_NAME=test-bucket MINIO_ACCESS_KEY=twój_klucz_dostępu_minio MINIO_SECRET_KEY=twój_tajny_klucz_minio MINIO_URL=twój_url_minio:twój_port_minio |
Plik env zawiera tekst zastępczy, który należy zmodyfikować i uzupełnić poprawnymi wartościami:
-
DJANGO_SECRET_KEY: Wygeneruj unikalną, nieprzewidywalną wartość, jak wyjaśniono w Django docs. Możesz użyć tego polecenia, aby wygenerować losowy ciąg znaków i przypisać go do zmiennej: python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())'.
-
DJANGO_ALLOWED_HOSTS: ta wartość służy do zabezpieczenia aplikacji przed atakami typu HTTP Host Header. Możesz ustawić ją na *, znak wieloznaczny pasujący do wszystkich hostów w trybie deweloperskim. Podczas wdrażania aplikacji na produkcję ustaw tę wartość na swoją zarejestrowaną nazwę domeny. W naszej demonstracji jest to example_domain.com.
-
DB_DATABASE: ustaw tę wartość na nazwę bazy danych PostgreSQL utworzonej w sekcji Prerequisites, w naszym przypadku jest to polls_db.
-
DB_USERNAME: ustaw tę wartość na nazwę użytkownika wybraną dla bazy danych.
-
DB_PASSWORD: ustaw tę wartość na hasło wybrane dla bazy danych.
-
DB_HOST: ustaw tę wartość na hosta, na którym działa instancja bazy danych, zgodnie z konfiguracją w sekcji Prerequisites. Zostało to wyjaśnione w krokach 1 i 2 samouczka Building a Django and Gunicorn Application with Docker on Ubuntu w celu skonfigurowania bazy danych.
-
DB_PORT: ustaw tę wartość na port swojej bazy danych.
Zapisz i zamknij plik po zakończeniu edycji. Po wprowadzeniu danych uwierzytelniających bazy danych możemy utworzyć schemat bazy danych, uruchamiając kontener i nadpisując instrukcję CMD ustawioną w pliku Dockerfile. Więcej informacji na ten temat można znaleźć w Dockerfile entry point from official Docs. Następnie wykonaj następujące polecenie:
|
1 |
docker run --env-file env django-polls:v1 sh -c "python manage.py makemigrations && python manage.py migrate" |
W tym poleceniu uruchamiamy obraz django-polls:v1 i przekazujemy zmodyfikowany wcześniej plik env. Część: sh -c "python manage.py makemigrations && python manage.py migrate” tworzy schemat bazy danych zdefiniowany przez kod aplikacji. Jeśli wykonujesz to polecenie po raz pierwszy, powinieneś zobaczyć podobny wynik wskazujący na utworzenie schematu bazy danych:
Po utworzeniu schematu możemy utworzyć superużytkownika Django. Wykonaj następujące polecenie, aby uruchomić kontener z interaktywną powłoką:
|
1 |
docker run -i -t --env-file env django-polls:v1 sh |
Polecenie uruchamia kontener z monitem powłoki, którego można użyć do interakcji z powłoką Pythona. Utwórzmy użytkownika za pomocą następującego polecenia:
|
1 |
python manage.py createsuperuser |
Postępuj zgodnie z monitami, aby podać nazwę użytkownika, adres e-mail i hasło. Wpisz ponownie hasło i naciśnij Enter, aby utworzyć użytkownika. Wyjdź z powłoki i zatrzymaj kontener, naciskając CTRL+D.
Następnie musimy ponownie uruchomić kontener, nadpisując domyślne polecenie poleceniem Django collectstatic. Polecenie to wygeneruje pliki statyczne dla aplikacji i prześle je do chmury pamięci masowej MinIO:
|
1 |
docker run --env-file env django-polls:v1 sh -c "python manage.py collectstatic --noinput" |
Polecenie generuje i przesyła pliki do skonfigurowanej usługi przechowywania obiektów. Oto wynik:
Możesz teraz uruchomić aplikację bez określania żadnego dodatkowego polecenia nadpisującego domyślną instrukcję CMD zdefiniowaną w pliku Dockerfile:
|
1 |
docker run --env-file env -p 80:8000 django-polls:v1 |
Docker uruchamia domyślne polecenie zdefiniowane w pliku Dockerfile, uruchamia kontener z serwerem gunicorn, udostępnia port kontenera 8000 i mapuje go na port systemu Ubuntu 80. Możesz teraz wyświetlić interfejs aplikacji w przeglądarce, wpisując adres IP pierwszego serwera w pasku adresu: http://FIRST_SERVER_IP.
Otrzymasz błąd 404 Page Not Found, ponieważ nie zdefiniowaliśmy niczego dla / ścieżkę. Przejdź do http://FIRST_SERVER_IP/polls, aby zobaczyć interfejs ankiet:
Odwiedź panel administracyjny, aby utworzyć ankiety: http://FIRST_SERVER_IP/admin:
Podaj dane uwierzytelniające ustawione za pomocą polecenia createsuperuser powyżej, aby uzyskać dostęp do panelu administracyjnego:
Jeśli wyświetlisz źródło strony, zauważysz, że pliki statyczne są pobierane ze zdefiniowanego kontenera pamięci (storage bucket). Po potwierdzeniu, że kontener obsługuje aplikację zgodnie z oczekiwaniami, możesz go zatrzymać, naciskając CTRL+C w terminalu.
Następnie musimy utrzymać działanie kontenera w trybie detached (odłączonym), abyśmy mogli zamknąć sesję SSH pierwszego serwera. Spowoduje to, że kontener będzie działał w tle. Wykonaj następujące polecenie:
|
1 |
docker run -d --rm --name polls --env-file env -p 80:8000 django-polls:v1 |
Flaga -d uruchamia kontener w trybie detached (odłączonym), dzięki czemu może on nadal działać w tle. Flaga --rm czyści system plików kontenera po jego zakończeniu. Nadajemy kontenerowi nazwę polls, abyśmy mogli go zobaczyć podczas listowania kontenerów.
Wyjdź z sesji SSH pierwszego serwera i przejdź do http://FIRST_SERVER_IP/polls w przeglądarce, aby potwierdzić, że działa zgodnie z oczekiwaniami. Jeśli widzisz interfejs ankiet, oznacza to, że Twój pierwszy serwer aplikacji został pomyślnie skonfigurowany. W następnym kroku skonfigurujmy drugi serwer aplikacji.
Krok 2: Konfiguracja drugiego serwera aplikacji
Sklonujemy zdokeryzowaną gałąź aplikacji, którą utworzyliśmy w samouczku Building a Django and Gunicorn Application with Docker on Ubuntu . Więcej szczegółów na temat poleceń, których tutaj użyjemy, znajdziesz w tym samouczku lub w wersji skróconej w Step 1.
Powinieneś mieć uruchomiony drugi serwer, dodanego użytkownika sudo niebędącego rootem oraz zainstalowanego Dockera, jak wyjaśniono w sekcji Prerequisites.
Następnym krokiem jest skonfigurowanie tego serwera do połączenia z instancją serwera PostgreSQL. Jak wyjaśniono w Kroku 1 samouczka Building a Django and Gunicorn Application with Docker on Ubuntu, musisz zezwolić na adres IP drugiego serwera w konfiguracji ufw oraz PostgreSQL.
Najpierw zaloguj się na instancję serwera bazy danych PostgreSQL jako użytkownik sudo niebędący rootem. Aby dodać regułę ufw, wykonaj następujące polecenie:
|
1 |
sudo ufw allow from SECOND_SERVER_IP to any port 5432 |
Następnie wykonaj to polecenie i dodaj adres IP drugiego serwera do pliku uwierzytelniania klienta PostgreSQL:
|
1 |
sudo nano /etc/postgresql/12/main/pg_hba.conf |
Przeczytaj komentarze, aby dowiedzieć się więcej o konfiguracji. Następnie dodaj tę linię w sekcji hosts, podając swój adres IP:
|
1 |
host all all SECOND_SERVER_IP/24 md5 |
Zapisz i zamknij plik po zakończeniu edycji.
Następnie zrestartuj usługę PostgreSQL, aby zmiany weszły w życie:
|
1 |
sudo service postgresql restart |
Wyloguj się z instancji serwera bazy danych PostgreSQL i przejdź do konfiguracji drugiej instancji serwera aplikacji.
Zaloguj się na second app server za pomocą ssh. Następnie sklonuj gałąź django-polls-branch repozytorium django-polls za pomocą następującego polecenia:
|
1 2 |
git clone --single-branch --branch django-polls-docker --depth 1 https://github.com/jaymoh/django-polls.git |
Przejdź do katalogu django-polls:
|
1 |
cd django-polls |
Następnie zbuduj obraz za pomocą następującego polecenia:
|
1 |
docker build -t django-polls:v1 . |
Po zakończeniu procesu budowania obrazu zmodyfikuj plik env o wartości konfiguracyjne, jak wyjaśniono w Step 1. Otwórz plik za pomocą nano:
|
1 |
nano env |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
DJANGO_SECRET_KEY=twój_tajny_klucz DEBUG= DJANGO_LOGLEVEL=info DJANGO_ALLOWED_HOSTS=twój_adres_IP_serwera DB_ENGINE=postgresql_psycopg2 DB_DATABASE=polls_db DB_USERNAME=hackins DB_PASSWORD=twoje_hasło_bazy_danych DB_HOST=twój_host_bazy_danych DB_PORT=twój_port_bazy_danych STATIC_DEFAULT_FILE_STORAGE=storages.backends.s3boto3.S3Boto3Storage STATIC_MINIO_BUCKET_NAME=test-bucket MINIO_ACCESS_KEY=twój_klucz_dostępu_minio MINIO_SECRET_KEY=twój_tajny_klucz_minio MINIO_URL=twój_adres_url_minio:twój_port_minio |
Zastąp teksty zastępcze rzeczywistymi wartościami dodanymi w Kroku 1. Pamiętaj, aby zmodyfikować zmienną DJANGO_ALLOWED_HOSTS w odpowiedni sposób. Zapisz i zamknij plik po zakończeniu. Zaktualizuj swoje dane uwierzytelniające MinIO w pliku env tak jak w poprzednim kroku.
Nowy kontener aplikacji możesz teraz uruchomić w trybie odłączonym za pomocą następującego polecenia:
|
1 |
docker run -d --rm --name polls --env-file env -p 80:8000 django-polls:v1 |
Polecenie to uruchamia kontener i pozwala mu działać w tle. Wyjdź z sesji ssh drugiego serwera aplikacji i przejdź do http://SECOND_SERVER_IP/polls w przeglądarce, aby potwierdzić, że działa zgodnie z oczekiwaniami. Powinieneś zobaczyć interfejs ankiet, jeśli wszystko poszło zgodnie z planem.
Masz teraz dwa serwery aplikacji uruchamiające tę samą kopię Twojej aplikacji. W następnym kroku skonfigurujesz kontener Nginx do pracy jako reverse proxy.
Krok 3: Konfiguracja kontenera Docker Nginx
Nginx to jedno z najpopularniejszych oprogramowań serwerów WWW o otwartym kodzie źródłowym na świecie. Odpowiada za zapewnienie dostępności i skalowalności witryn o największym natężeniu ruchu w Internecie. Gwarantuje bezpieczeństwo i jest bardzo wszechstronny. Możesz go używać do odwróconego proxy, buforowania i równoważenia obciążenia. Skonfigurowaliśmy naszą aplikację tak, aby korzystała z oddzielnej usługi przechowywania obiektów do obsługi plików statycznych i multimedialnych. W związku z tym nie będziemy korzystać z funkcji buforowania Nginx. Zamiast tego użyjemy funkcji odwróconego proxy i równoważenia obciążenia Nginx. Serwer Nginx przyjmie ruch przychodzący i rozdzieli go na serwery aplikacji zaplecza. Następnie zapewni bezpieczną komunikację między klientem a serwerem, zabezpieczając ruch za pomocą certyfikatów SSL uzyskanych od Let’s Encrypt.
Istnieje kilka sposobów na wdrożenie odwróconego proxy i równoważenia obciążenia w Nginx. Jednym ze sposobów jest ustawienie odwróconego proxy Nginx oddzielnie od serwera aplikacji zaplecza, tak jak zrobiliśmy to w tym samouczku. Taka konfiguracja jest elastyczna i pozwala na skalowanie zarówno warstwy proxy Nginx, jak i warstwy aplikacji. Możesz dodać wiele serwerów proxy Nginx lub wdrożyć chmurowy moduł równoważenia obciążenia. Innym sposobem wdrożenia odwróconego proxy jest użycie jednego z serwerów aplikacji zaplecza jako proxy Nginx. Wtedy możesz przekierowywać przychodzące żądania lokalnie oraz do innych serwerów aplikacji. Opcjonalnie możesz skonfigurować kontener Nginx na wszystkich serwerach aplikacji zaplecza i ustawić zewnętrzny chmurowy moduł równoważenia obciążenia do odbierania ruchu przychodzącego i dystrybuowania go do serwerów aplikacji zaplecza.
Zacznijmy konfigurować serwer proxy. Zaloguj się na czwarty serwer Ubuntu, który został przeznaczony do użytku jako proxy Nginx, i utwórz katalog konfiguracyjny:
|
1 |
mkdir conf |
Otwórz plik konfiguracyjny za pomocą nano wewnątrz tego katalogu:
|
1 |
nano conf/nginx.conf |
Następnie dodaj do pliku następującą konfigurację:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
upstream django { server FIRST_SERVER_IP; server SECOND_SERVER_IP; } server { listen 80 default_server; return 444; } server { listen 80; listen [::]:80; server_name example_domain.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name example_domain.com; # SSL ssl_certificate /etc/letsencrypt/live/example_domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example_domain.com/privkey.pem; ssl_session_cache shared:le_nginx_SSL:10m; ssl_session_timeout 1440m; ssl_session_tickets off; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers off; ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; client_max_body_size 4G; keepalive_timeout 5; location / { 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_redirect off; proxy_pass http://django; } location ^~ /.well-known/acme-challenge/ { root /var/www/html; } } |
W tym pliku konfiguracyjnym określamy bloki server, upstream, oraz location, aby poinstruować Nginx o przekierowywaniu żądań HTTP na HTTPS i dystrybucji żądań pomiędzy dwoma serwerami aplikacji skonfigurowanymi w Kroku 1 i Kroku 2. Ogólne informacje o strukturze pliku konfiguracyjnego Nginx można znaleźć w ich oficjalnej dokumentacji.
Przeanalizowaliśmy pliki konfiguracyjne dostarczone przez Docker Hub w dokumentacji obrazu Nginx, Certbot, oraz Gunicorn aby stworzyć ten minimalny plik konfiguracyjny Nginx. Chociaż służy on wyłącznie do celów demonstracyjnych i uruchomienia naszej konfiguracji, możesz swobodnie badać i eksperymentować z innymi konfiguracjami, postępując zgodnie z poradnikami Nginx.
Blok upstream służy do definiowania grupy serwerów, które będą przetwarzać przychodzące żądania. nazwa jest nadawana grupie i jest wywoływana przez dyrektywę proxy_pass. Nazwaliśmy ten blok django i określiliśmy adresy IP dwóch serwerów aplikacji backendowej:
|
1 2 3 4 |
upstream django { server FIRST_SERVER_IP; server SECOND_SERVER_IP; } |
Zdefiniowaliśmy również 3 bloki serwera. pierwszy blok serwera przechwytuje wszystkie żądania, które nie pasują do Twojej domeny, i zwraca 444 kod (zamyka połączenie bez wysyłania odpowiedzi do klienta, odrzucając w ten sposób złośliwe lub nieprawidłowo sformułowane żądania). Bezpośrednie żądanie HTTP na adres IP Twojego serwera jest obsługiwane przez ten blok, ponieważ jest on zdefiniowany jako default_server:
|
1 2 3 4 |
server { listen 80 default_server; return 444; } |
The Drugi blok serwera obsługuje przychodzące żądania HTTP (port 80) i przekierowuje je do HTTPS (port 443) przy użyciu przekierowania HTTP 301:
|
1 2 3 4 5 6 |
server { listen 80; listen [::]:80; server_name example_domain.com; return 301 https://$server_name$request_uri; } |
Trzeci blok serwera obsługuje teraz żądania. Zawiera on kilka dyrektyw, a ich znaczenie wyjaśnimy poniżej.
Mamy dwie dyrektywy definiujące ścieżki do certyfikatu TLS i klucza dostarczonych przez Certbot. Certyfikaty są montowane w kontenerze Nginx podczas jego uruchamiania:
|
1 2 3 |
# SSL ssl_certificate /etc/letsencrypt/live/example_domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example_domain.com/privkey.pem; |
Następnie mamy domyślne ustawienia bezpieczeństwa SSL zalecane przez Certbot. Więcej informacji można znaleźć w oficjalnej dokumentacji Nginx dotyczącej modułu ngx_http_ssl_module. Mozilla oferuje również więcej informacji na temat bezpieczeństwa po stronie serwera. Wartość ssl_ciphers w pliku conf została pobrana ze strony Mozilli:
|
1 2 3 4 5 6 |
ssl_session_cache shared:le_nginx_SSL:10m; ssl_session_timeout 1440m; ssl_session_tickets off; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers off; ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; |
W kolejnych dwóch dyrektywach zdefiniujemy maksymalny dozwolony rozmiar treści żądania klienta i ustawimy limit czasu dla połączeń keep-alive z klientem. Nginx zamknie połączenia z klientem po liczbie sekund ustawionej w dyrektywie keepalive_timeout. Więcej informacji na temat konfiguracji Nginx do wdrażania Gunicorn można znaleźć w oficjalnej dokumentacji:
|
1 2 |
client_max_body_size 4G; keepalive_timeout 5; |
W pliku konfiguracyjnym zdefiniowaliśmy również dwa bloki lokalizacji (location). Pierwszy blok obsługuje przekazywanie (proxying) żądań zgodnie z definicją w dyrektywach proxy. Przychodzące żądania są przekazywane do serwerów upstream django zdefiniowanych wcześniej:
|
1 2 3 4 5 6 7 |
location / { 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_redirect off; proxy_pass http://django; } |
Więcej informacji na temat dyrektyw proxy można znaleźć w Nginx Module ngx_http_proxy_module oraz w dokumentacji dotyczącej wdrażania serwera Gunicorn.
W drugim bloku location definiujemy ścieżkę: /well-known/acme-challenge/. Jest ona zazwyczaj używana przez Certbot do weryfikacji nazwy domeny w Let’s Encrypt przed wygenerowaniem lub odnowieniem certyfikatu SSL:
|
1 2 3 |
location ^~ /.well-known/acme-challenge/ { root /var/www/html; } |
To wszystko, jeśli chodzi o plik konfiguracyjny Nginx. Po zakończeniu edycji możesz zapisać i zamknąć plik.
Zdefiniowany właśnie plik konfiguracyjny może zostać użyty do uruchomienia kontenera Nginx. Jednak zakończy się to niepowodzeniem, ponieważ nie wygenerowaliśmy jeszcze certyfikatów SSL z Let’s Encrypt. W tym samouczku użyjemy nginx:1.20.2 obrazu Docker w wersji 1.20.2 z oficjalnego Nginx image repository on Docker Hub.
Możesz uruchomić poniższe polecenie, aby pobrać obraz i zweryfikować, czy wszystko działa poprawnie:
|
1 2 3 4 |
docker run --rm --name nginx -p 80:80 -p 443:443 \ -v ~/conf/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro \ -v /var/www/html:/var/www/html \ nginx:1.20.2 |
To polecenie tworzy kontener o nazwie nginx i mapuje porty 80 i 443 między systemem hosta a kontenerem. Flaga --rm usuwa wszelkie kontenery pośrednie po pomyślnym zbudowaniu. Używamy flagi -v do zamontowania pliku konfiguracyjnego w kontenerze w /etc/nginx/conf.d/nginx.conf, który jest domyślnym katalogiem konfiguracji Nginx. Jest on montowany w trybie tylko do odczytu za pomocą flagi ro, aby zapobiec modyfikowaniu go przez kontener Nginx. Ustawiamy domyślny katalog webroot i montujemy go jako /var/www/html. Na koniec instruujemy Dockera, aby użył obrazu nginx:1.20.2 do tej kompilacji. W następnym kroku uzyskajmy certyfikat TLS/SSL i klucz z Let’s Encrypt.
Krok 4: Generowanie certyfikatu SSL/TLS z Let’s Encrypt i konfigurowanie automatycznego odnawiania Certbot
Certbot pomaga generować bezpłatne certyfikaty TLS z Let’s Encrypt oraz zarządzać ich automatycznym odnawianiem przed wygaśnięciem. Zwiększa to bezpieczeństwo Twoich stron internetowych i zapewnia, że są one obsługiwane przez HTTPS. Aby zachować kontenerowy charakter naszej architektury, użyjemy obrazu Docker Certbot do pobrania certyfikatów SSL/TLS i skonfigurowania automatycznego odnawiania. Upewnij się, że masz zainstalowanego Dockera na swoim serwerze proxy zgodnie z instrukcjami w sekcji Wymagania wstępne.
Powinieneś również posiadać rekord DNS A dla swojej zarejestrowanej nazwy domeny, wskazujący na adres IP serwera proxy. Możesz to zweryfikować, uruchamiając obraz Docker certbot i przekazując flagę --staging:
|
1 2 3 4 |
docker run -it --rm -p 80:80 --name certbot \ -v "/etc/letsencrypt:/etc/letsencrypt" \ -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \ certbot/certbot certonly --standalone --staging -d example_domain.com |
Polecenie pobierze obraz Certbot i uruchomi go w trybie interaktywnym. Oznacza to, że zostanie uruchomiony z powłoką (shell), co umożliwi wprowadzenie niektórych danych. Mapuje ono port 80 hosta na port 80 wewnątrz kontenera. Używamy flagi -v do zamontowania dwóch katalogów hosta w kontenerze: /etc/letsencrypt/ i /var/lib/letsencrypt/. Flaga --standalone flaga określa, że chcemy, aby obraz Certbot działał bez użycia Nginx. Na koniec mamy --staging flagę, która spowoduje, że Certbot uruchomi się na serwerach stagingowych i zweryfikuje Twoją nazwę domeny.
Wprowadź swój adres e-mail i zaakceptuj Warunki korzystania z usługi po wyświetleniu monitu. Poniżej znajduje się wynik pomyślnej walidacji:
|
1 2 3 4 5 6 7 |
Konto zarejestrowane. Żądanie o certyfikat dla example_domain.com Pomyślnie otrzymano certyfikat. Certyfikat jest zapisany w: /etc/letsencrypt/live/example_domain.com/fullchain.pem Klucz jest zapisany w: /etc/letsencrypt/live/example_domain.com/privkey.pem Ten certyfikat wygasa w dniu 2022-04-29. Te pliki zostaną be zaktualizowane, gdy the certyfikat się odnowi. |
KOLEJNE KROKI:
Certyfikat będzie musiał zostać odnowiony przed wygaśnięciem. Certbot może automatycznie odnawiać certyfikat w tle, ale może być konieczne podjęcie kroków w celu włączenia tej funkcjonalności. Sprawdź ten link w celu uzyskania instrukcji.
Możesz wyświetlić certyfikat za pomocą polecenia cat :
|
1 |
sudo cat /etc/letsencrypt/live/example_domain.com/fullchain.pem |
Powyższe polecenie powinno wyświetlić Twój certyfikat w terminalu. Po potwierdzeniu, że Certbot dostarczył Twój certyfikat, możesz teraz przetestować konfigurację Nginx utworzoną w Kroku 3. Wykonaj poniższe polecenie Docker, aby uruchomić kontener Nginx:
|
1 2 3 4 5 6 |
docker run --rm --name nginx -p 80:80 -p 443:443 \ -v ~/conf/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro \ -v /etc/letsencrypt:/etc/letsencrypt \ -v /var/lib/letsencrypt:/var/lib/letsencrypt \ -v /var/www/html:/var/www/html \ nginx:1.20.2 |
W tym poleceniu użyliśmy flagi -v do zamontowania lokalizacji katalogów certyfikatów SSL/TLS Let’s Encrypt.
Gdy kontener zostanie uruchomiony, otwórz stronę internetową w przeglądarce: http://example_domain.com. Prawdopodobnie zobaczysz ostrzeżenie, że witryna jest niebezpieczna:
Dzieje się tak, ponieważ dostarczyliśmy tylko certyfikaty stagingowe/testowe, a nie produkcyjne certyfikaty od Let’s Encrypt. Uzyskajmy certyfikaty produkcyjne, wykonując następujące polecenie Certbot bez flagi --staging flag:
|
1 2 3 4 |
docker run -it --rm -p 80:80 --name certbot \ -v "/etc/letsencrypt:/etc/letsencrypt" \ -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \ certbot/certbot certonly --standalone -d example_domain.com |
W monicie potwierdź, że chcesz odnowić i zastąpić istniejący certyfikat, wpisując 2 i naciśnij ENTER. Powinno to dostarczyć certyfikat gotowy do użycia produkcyjnego. Możesz teraz uruchomić kontener Nginx i wszystko powinno działać poprawnie:
|
1 2 3 4 5 6 |
docker run --rm --name nginx -p 80:80 -p 443:443 \ -v ~/conf/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro \ -v /etc/letsencrypt:/etc/letsencrypt \ -v /var/lib/letsencrypt:/var/lib/letsencrypt \ -v /var/www/html:/var/www/html \ nginx:1.20.2 |
Gdy kontener zostanie uruchomiony, ponownie otwórz stronę internetową w przeglądarce: http://example_domain.com ponownie. Zauważ, że Twoja przeglądarka jest przekierowywana na HTTPS nawet jeśli wpiszesz HTTP. Oznacza to, że nasz serwer w konfiguracji Nginx, jak również dostarczone certyfikaty SSL/TLS działają poprawnie. Przejdź do ścieżki polls trasy http://example_domain.com/polls, ponieważ nie mamy zdefiniowanej trasy dla ścieżki głównej /. Powinieneś zobaczyć interfejs ankiet:
Do tej pory pomyślnie skonfigurowałeś architekturę gotową do wdrożenia produkcyjnego. Zaimplementowałeś dwa serwery backendowe, które będą przetwarzać przychodzące żądania przekazywane przez serwer proxy. Serwer proxy zajmie się równoważeniem obciążenia i zabezpieczaniem ruchu za pomocą dostarczonych certyfikatów TLS.
Należy jednak pamiętać, że certyfikaty Let’s Encrypt wygasają po 90 dniach. W związku z tym należy je odnowić przed upływem tego terminu. Ponieważ kontener Nginx będzie uruchomiony, należy użyć trybu webroot zamiast trybu standalone podczas wykonywania polecenia certbot w celu odnowienia certyfikatu. Pamiętaj, że określiłeś katalog /var/www/html/.well-known/acme-challenge/ w pliku konfiguracyjnym Nginx w Kroku 3. Certbot użyje tej ścieżki do przechowywania plików weryfikacyjnych. Ponadto klient Let’s Encrypt będzie odpytywał tę ścieżkę żądaniami weryfikacyjnymi podczas próby odnowienia certyfikatów. Po zakończeniu wykonywania polecenia odnowienia możesz przeładować Nginx, aby zastosować zmiany.
Zatrzymaj kontener, naciskając CTRL+C w terminalu i uruchommy go ponownie w trybie odłączonym (detached) z flagą -d:
|
1 2 3 4 5 6 |
docker run --rm --name nginx -d -p 80:80 -p 443:443 \ -v ~/conf/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro \ -v /etc/letsencrypt:/etc/letsencrypt \ -v /var/lib/letsencrypt:/var/lib/letsencrypt \ -v /var/www/html:/var/www/html \ nginx:1.20.2 |
Spowoduje to pozostawienie kontenera Nginx działającego w tle. Przetestujmy procedurę odnawiania certyfikatu z flagą --dry-run, wykonując poniższe polecenie:
|
1 2 3 4 5 |
docker run -it --rm --name certbot \ -v "/etc/letsencrypt:/etc/letsencrypt" \ -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \ -v "/var/www/html:/var/www/html" \ certbot/certbot renew --webroot -w /var/www/html --dry-run |
W tym poleceniu określiliśmy wtyczkę --webroot oraz ścieżkę do użycia przy żądaniach weryfikacyjnych za pomocą flagi -w. Określamy również flagę --dry-run, aby zweryfikować procedurę automatycznego odnawiania bez rzeczywistego generowania certyfikatu.
W przypadku pomyślnej symulacji powinieneś zobaczyć podobny wynik:
|
1 2 3 4 5 6 7 8 |
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Processing /etc/letsencrypt/renewal/example_domain.com.conf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Simulating renewal of an existing certificate for example_domain.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Congratulations, all simulated renewals succeeded: /etc/letsencrypt/live/hackinroms.com/fullchain.pem (success) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
Za każdym razem, gdy odnawiasz certyfikat dla działającej aplikacji, musisz przeładować Nginx, aby kontener zaczął używać nowego certyfikatu. Poniższe polecenie platformy Docker przeładowuje kontener nginx (pamiętaj, że nazwaliśmy ten kontener nginx):
|
1 |
docker kill -s HUP nginx |
Polecenie wysyła sygnał Unix HUP do procesu Nginx działającego wewnątrz kontenera Docker nginx. Powoduje to, że Nginx przeładowuje swoje konfiguracje i zaczyna używać odnowionych certyfikatów.
Ponieważ mamy zainstalowany protokół TLS/SSL na naszym serwerze proxy, a nasza strona internetowa jest obsługiwana przez HTTPS, musimy teraz zabezpieczyć nasze serwery aplikacji backendowych, aby zezwalały na żądania wyłącznie z serwera proxy.
Krok 5: Zabezpieczanie backendowych serwerów Django przed dostępem zewnętrznym
Serwer proxy wdrożony w tym samouczku obsługuje terminację SSL, w ramach której deszyfruje połączenie SSL i przekazuje niezaszyfrowane pakiety do serwerów aplikacji zaplecza. Ponieważ będziemy zabezpieczać serwery zaplecza przed jakimkolwiek dostępem zewnętrznym, ten poziom bezpieczeństwa powinien sprawdzić się w większości przypadków. Jeśli jednak wdrażasz aplikacje przesyłające wrażliwe dane, takie jak informacje bankowe lub dane medyczne, należy wdrożyć szyfrowanie end-to-end.
W tym samouczku serwery Gunicorn na zapleczu są chronione przez Nginx, ponieważ nie są przeznaczone do bezpośredniego kontaktu z użytkownikami. Serwer proxy Nginx działa jak brama do serwerów zaplecza, uniemożliwiając zewnętrznym klientom bezpośredni dostęp do serwerów aplikacji zaplecza. Upewnij się, że wszystkie żądania przechodzą przez serwer proxy. W związku z tym Docker ma pewien problem polegający na omijaniu reguł ufw i otwieraniu portów na zewnątrz, co może pozostawić infrastrukturę niezabezpieczoną. Jest to widoczne, ponieważ skonfigurowaliśmy nasze serwery aplikacji w Kroku 1 i Kroku 2 bez zezwolenia na port 80 w regułach ufw. Jednak nadal można uzyskać dostęp do stron internetowych po przejściu pod dowolny z publicznych adresów IP serwera w przeglądarce. Jednym ze sposobów na rozwiązanie tego problemu jest użycie iptables bezpośrednio, bez przechodzenia przez ufw. Więcej informacji można znaleźć w oficjalnych dokumentach Docker i iptables, aby dowiedzieć się więcej. Innym zalecanym sposobem jest użycie zapór sieciowych w chmurze.
Zmodyfikujmy konfigurację UFW, aby zablokować zewnętrzny dostęp do wszystkich portów, które mogły zostać otwarte przez Dockera. Kiedy zmapowaliśmy port hosta 80 na port kontenera Dockera 8000 za pomocą flagi -p 80:8000 w poleceniu Dockera, nieumyślnie otworzyliśmy również port 80 na maszynie hosta. Możesz wyłączyć ten dostęp, modyfikując konfigurację UFW zgodnie z opisem w repozytorium ufw-docker README.
Wprowadźmy zmiany dla pierwszego serwera aplikacji Django. Zaloguj się na serwer i otwórz plik w lokalizacji /etc/ufw/after.rules za pomocą nano jako użytkownik sudo:
|
1 |
sudo nano /etc/ufw/after.rules |
Plik zawiera następujące reguły ufw:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# # rules.input-after # # Reguły, które powinny być uruchamiane po regułach dodanych z wiersza poleceń ufw. Niestandardowe # reguły powinny być dodawane do jednego z tych łańcuchów: # ufw-after-input # ufw-after-output # ufw-after-forward # # Nie usuwaj tych wymaganych linii, w przeciwnym razie wystąpią błędy *filter :ufw-after-input - [0:0] :ufw-after-output - [0:0] :ufw-after-forward - [0:0] # Koniec wymaganych linii # domyślnie nie loguj hałaśliwych usług -A ufw-after-input -p udp --dport 137 -j ufw-skip-to-policy-input -A ufw-after-input -p udp --dport 138 -j ufw-skip-to-policy-input -A ufw-after-input -p tcp --dport 139 -j ufw-skip-to-policy-input -A ufw-after-input -p tcp --dport 445 -j ufw-skip-to-policy-input -A ufw-after-input -p udp --dport 67 -j ufw-skip-to-policy-input -A ufw-after-input -p udp --dport 68 -j ufw-skip-to-policy-input # domyślnie nie loguj hałaśliwych rozgłoszeń -A ufw-after-input -m addrtype --dst-type BROADCAST -j ufw-skip-to-policy-input # nie usuwaj linii 'COMMIT', w przeciwnym razie te reguły nie zostaną przetworzone COMMIT |
Dodaj następujący blok linii konfiguracji UFW na dole pliku:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# BEGIN UFW AND DOCKER *filter :ufw-user-forward - [0:0] :DOCKER-USER - [0:0] -A DOCKER-USER -j RETURN -s 10.0.0.0/8 -A DOCKER-USER -j RETURN -s 172.16.0.0/12 -A DOCKER-USER -j RETURN -s 192.168.0.0/16 -A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN -A DOCKER-USER -j ufw-user-forward -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16 -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8 -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12 -A DOCKER-USER -j RETURN COMMIT # END UFW AND DOCKER |
Dodane reguły uniemożliwiają publiczny dostęp do portów otwieranych przez Dockera. Ponadto umożliwiają one dostęp z 10.0.0.0/8, 172.16.0.0/12, oraz 192.168.0.0/16 prywatnych zakresów adresów IP. Więcej szczegółów na temat tych reguł można znaleźć w README ufw-docker. Zapisz i zamknij pliki po zakończeniu edycji. Ta konfiguracja powinna działać, jeśli skonfigurowano sieć wirtualnej chmury prywatnej (VPC) ze wszystkimi trzema serwerami w VPC, a następnie określono prywatne adresy IP serwerów Django w dyrektywie upstream pliku konfiguracyjnego Nginx.
Jednak użyliśmy publicznych adresów IP i możemy nie mieć VPC. Dlatego musisz dodać regułę do ufw zezwalającą na ruch z serwera proxy Nginx przez port 80 obu serwerów aplikacji Django. Możesz dodać regułę zezwalającą do ufw określającą źródłowy adres IP serwera dla portu 80 za pomocą następującego polecenia:
|
1 |
sudo ufw allow from NGINX_PROXY_IP to any port 80 |
Po zakończeniu modyfikacji uruchom ponownie serwer aplikacji Django, aby zmiany weszły w życie, ponieważ uruchomienie sudo ufw reload wydaje się nie przynosić skutków:
|
1 |
sudo reboot |
Po ponownym uruchomieniu serwera uruchom kontener tak, jak w Kroku 1 lub Kroku 2:
|
1 |
docker run -d --rm --name polls --env-file env -p 80:8000 django-polls:v1 |
Następnie spróbuj odwiedzić adres IP pierwszego serwera Django w przeglądarce, aby sprawdzić, czy wyświetla interfejs Polls: http://FIRST_SERVER_IP/polls. To się nie powiedzie. Teraz wyloguj się z pierwszego serwera i powtórz wykonane tutaj kroki dla drugiego serwera. Otwórz plik /etc/ufw/after.rules za pomocą nano jako użytkownik sudo:
|
1 |
sudo nano /etc/ufw/after.rules |
Tak jak poprzednio, przewiń na sam dół i dodaj blok konfiguracji UFW:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# BEGIN UFW AND DOCKER *filter :ufw-user-forward - [0:0] :DOCKER-USER - [0:0] -A DOCKER-USER -j RETURN -s 10.0.0.0/8 -A DOCKER-USER -j RETURN -s 172.16.0.0/12 -A DOCKER-USER -j RETURN -s 192.168.0.0/16 -A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN -A DOCKER-USER -j ufw-user-forward -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16 -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8 -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12 -A DOCKER-USER -j RETURN COMMIT # END UFW AND DOCKER |
Zapisz i zamknij plik po dodaniu powyższego bloku.
Następnie dodaj regułę zezwalającą do ufw określając źródłowy adres IP serwera do portu 80 za pomocą następującego polecenia:
|
1 |
sudo ufw allow from NGINX_PROXY_IP to any port 80 |
Uruchom ponownie serwer, aby zmiany weszły w życie:
|
1 |
sudo reboot |
Gdy serwer uruchomi się ponownie, uruchom kontener jeszcze raz za pomocą polecenia:
|
1 |
docker run -d --rm --name polls --env-file env -p 80:8000 django-polls:v1 |
Sprawdź, czy możesz wyświetlić interfejs ankiet, przechodząc bezpośrednio pod adres IP drugiego serwera: http://SECOND_SERVER_IP/polls. To również powinno się nie powieść.
Ta architektura jest teraz gotowa do przetestowania. Możesz odwiedzić https://example_domain_here/polls aby wyświetlić domyślny interfejs ankiet w przeglądarce. Oznacza to, że serwer proxy Nginx nadal ma dostęp do serwerów backendowych Django.
Podsumowanie
W tym poradniku pokazaliśmy, jak wdrożyć skalowalną infrastrukturę przy użyciu kontenerów Docker. Infrastruktura ta obejmuje oddzielny serwer bazy danych PostgreSQL, dwa serwery aplikacji backendowych oraz serwer proxy Nginx do równoważenia obciążenia i dystrybucji ruchu między tymi dwoma serwerami. Choć naszą aplikację oparliśmy na aplikacji Django Polls, możesz dostosować tę architekturę do różnych aplikacji korzystających z innych frameworków, takich jak Node.js, Laravel, itp.
To są podstawowe wskazówki na start. Kilka ulepszeń, które możesz wprowadzić, to umieszczenie obrazu w repozytorium obrazów, takim jak Docker Hub co pozwoli na łatwą dystrybucję obrazu na wiele serwerów. Możesz również dodać potoki ciągłej integracji i wdrażania (CI/CD), aby automatycznie budować, testować i wdrażać obrazy na serwerach aplikacji po wystąpieniu określonego zdarzenia. Na przykład zdarzeniem może być przesłanie nowego kodu do określonej gałęzi w repozytorium git. Możesz także zautomatyzować działania w przypadku napotkania błędu przez kontener. Oficjalna dokumentacja Dockera zawiera dobre wskazówki dotyczące automatycznego uruchamiania kontenerów w przypadku błędów lub ponownego uruchomienia systemu.
Powodzenia!








Komentarze
Brak komentarzy. Bądź pierwszy.