Chmury obliczeniowe, devops, programowanie ...

... moje doświadczenia w poszukiwaniu rozwiązań - Marcin Frątczak

[MyFood] Docker – api, web, loadbalancing, ssl (darmowy),mysql – pełny config

Nadszedł czas wdrożenia środowiska developerskiego, oraz środowiska produkcyjnego. Od początku moim planem było wykorzystanie dockera. Dzięki niemu łatwo wszystko postawić na nowym serwerze. Najtrudniejsze jak zwykle było stworzenie pierwszy raz kompleksowej konfiguracji, z wszystkimi elementami, które są potrzebne w każdym projekcie.

Co to docker przeczytać możesz tutaj: 1, 23

Spis wszystkich kontenerów

  • serwer api
  • serwer api2 (drugi serwer do testu loadbalancingu – normalnie w swoim projekcie nie używam, dlatego jest to kopiuj / wklej api)
  • serwer web
  • baza danych (mysql)
  • phpmyadmin (tylko dla dev)
  • haproxy
  • letsencrypt (odnawiany 90 dniowy certyfikat SSL)

Dlaczego tyle kontenerów i w czym problem

Zasadą w świecie dockera jest „1 kontener = 1 zadanie” . A więc nie powinno w jednym kontenerze instalować się kilku funkcjonalności: serwer www, skrypty (np php), baza danych. Bardzo ciężko pilnować gdy coś się popsuje , oraz ciężko wgrać aktualizacje do systemu. Dlatego wszystko wydzielamy do kontenerów, która lista jest powyżej.

Problem:

Nie można do kilku kontenerów przydzielić tego samego portu.

Czyli nie można jak niżej:

  • web – nasłuchuje na porcie 80
  • api – nasłuchuje na porcie 80

Przy próbie odpalenia pojawi się błąd:

Co oznacza tyle że port już jest używany i nie można odpalić kontenera. Jest to oczywiście logiczne, bo jak wchodzimy np na localhost, to system by nie wiedział na który kontener przekierować ruch.

Kolejny problem to domeny. Konfiguracja dockera nie używa takiego pojęcia jak domena / subdomena. Każdy kontener sam powinien rozpoznawać domenę, i serwować odpowiednie dane.

W konfiguracji dockera nie możemy podzielić ruchu dla danej domeny i dla danego portu.

Jak to zrobić?

Musimy sami to obsłużyć prz pomocy serwera proxy. Użytkownik wchodzi na stronę w danej domenie, to serwer proxy wyświetla mu dane z odpowiedniego kontenera dockera.

Serwer proxy rozpoznaje domene, oraz port, i odpowiednio serwuje dane.

Rozwiązań jest kilka, np:

  • na serwerze (host) instalujemy proxy i w konfiguracji ustawiamy i przekierowujemy domenę na dany kontener (1)
  • wykorzystujemy tylko kontenery dockerowe, i serwer proxy również jest w nim (2)

Wybieram rozwiązanie 2. – dobrze jest mieć porządek :)

Serwer Proxy – HAProxy – Load Balancing – SSL

Postawienie proxy, pozwala nam zainstalować również certyfikaty SSL, i je odpowiednio skonfigurować. Nie trzeba tego robić w każdym kontenerze. Wystarczy w jednym :)

Wykorzystamy tutaj certyfikaty „Let’s encrypt” https://letsencrypt.org/ – pozwala nam to za DARMO posiadać na swojej domenie ssl.

Certyfikat jest ważny 90 dni. Całe generowanie i pobieranie jest automatyczne, więc nie musimy się o to martwić.  PEŁNA AUTOMATYKA !

Serwer proxy również umożliwia wykorzystanie loadbalancingu. Co to jest? Jeśli ustawimy dla danego adresu np: https://api.myfood.love/ dwa kontenery. To proxy dzieli ruch po połowie i wysyła go to kontenera. Jak wejdziesz na testowy serwer api to po odświeżeniu strony będą się na przemiennie pojawiać informacje:

Ip:xxx.xxx.xxx.xxx Host: 8ca086de8527

oraz

Ip: xxx.xxx.xxx.xxx Host: cccc89c4b35c

Dla przykładu wyświetlam ip oraz host. Host się zmienia w zależności od wybranego kontenera.

Po co load balancing?

Jeśli strona posiada duży ruch i maszyna nie wytrzymuje, to można dodać kolejną maszynę i obsłużyć dwa razy większy ruch. Klient nawet nie zauważy że ruch idzie z dwóch maszyn.

Konfiguracja środowiska – docker-compose.yml

Wszystkie obrazy jakie wykorzystuje znajdują się w pliku docker-compose.yml. Dzięki temu wystarczy odpalić jedno polecenie (docker-compose up -d) i dzieje się magia.

Oddzielnie stworze post z poleceniami, trickami itp, więc tutaj tylko suche fakty na temat pliku konfiguracyjnego :)

Aktualnie cały plik konfiguracyjny jest w wersji „3.1”. Oznacz to, że wersja dockera jaka powinna być to min. 1.13, a wersja docker-compose 1.11

Pełny plik konfiguracyjny (api z load balancingiem)

Pełne wyjaśnienie – hierarchia plików i katalogów https://github.com/mfratczak/myfood-generator

api.myfood.love – load balancing z api i api2

  • build – budowanie kontenera gdzie plik Dockerfile znajduje się w podkatalogu
    • context: Docker/python – katalog kontenera (Docker/python)
    • dockerfile: Dockerfile – nazwa pliku z konfiguracją kontenera, można np zmienic na Dockerfile-dev i będą ustawienia developerskie (jeśli taki plik istnieje)
  • environment: – zmienne systemowe przekazywane do środka kontenera
    • FORCE_SSL=yes – zmienna wykorzystywana w kontenerze haproxy – bardzo ważna zmienna dla haproxy i certyfikatu SSL
    • VIRTUAL_HOST=xxx – spis hostów które kierować mają na dany kontener, można podać kilka  – bardzo ważna zmienna dla haproxy i certyfikatu SSL
  • volumes: – mapowanie katalogów, aby projekt znajdował się poza kontenerem. Dzięki temu można usunąć całkowicie kontenery i utworzyć jeszcze raz a dane zostają
    • ./WebServer:/app – w katalogu WebServer znajduje się cały projekt systemu Api
  • links: – połączenie między kontenerami, kontener API ma dostęp do kontenera MYSQŁ, gdzie znajduje się baza danych
  • command: python server.py – możliwość zadeklarowania polecenia z jakim ma się uruchomić kontener, tutaj odpala serwer pythona, można dla wersji developerskiej zrobić np: python server-dev.py, czyli odpalić serwer pythona z ustawieniami pełnego logowania itp
  • restart: always – deklaracja co ma się stać jak kontener padnie, lub polecenie (python server.py) spowoduje błąd, czyli szybki restart maszyny
  • network_mode: „bridge” – wybór podsieci

Drobne wyjaśnienie odnośnie network_mode. Normalnie wszystkie kontenery z danego katalogu (z jednego pliku dockerfile) znajdują się w osobnej podsieci. Okazuje się, że serwer proxy działa tylko w głównej podsieci o nazwie „bridge”, dlatego wszystkie kontenery są dodane do niej.

Drugie drobne wyjaśnienie to FORCE_SSL. Dla testów lokalnych linijkę tą mam wyłączoną, ponieważ dla lokalnych domen (localhost, itp) nie można utworzyć certyfikatu

Ustawienie: VIRTUAL_HOST w api i w api2 na te same domeny powoduje, że proxy stosuje load balancing i dzieli ruch między te dwa kontenery.

myfood.love – serwer web

W pliku konfiguracyjnym powyżej, tworzę również serwer pythona do testów. Jednak różnicą jest zmiana w VIRTUAL_HOST, co powoduje, że ruch tutaj jest obsługiwany tylko przez jeden kontener.

W przyszłości tutaj będzie zmiana pliku konfiguracyjnego na ten z katalogu Docker/npm/Dockerfile (teraz jest tylko szybka kopia aby sprawdzić działanie haproxy)

– mysql oraz phpmyadmin

  • image: sameersbn/mysql:latest – popularny gotowy obraz mysql (posiadają również postgresql itp)
  • volumes: – ./Data/database:/var/lib/mysql – cała baza została wydzielona do podkatalogu database. Dzięki temu można wyłaczać i włączać kontener bazodanowy bez utraty danych
  • environment – zmienne z danymi do utworzenia pustej bazy

oraz

  • image: phpmyadmin/phpmyadmin – gotowy obraz z phpmyadminem
  • ports: – „9999:80” – kontener dostępny np pod localhost:9999 lokalnie, lub myfood.love:9999 w sieci, w wersji produkcyjnej dostęp do phpmyadmina powinien być WYŁĄCZONY!!!
  • environment: PMA_HOST: mysql – zmienna wskazuje na kontener w której jest baza

Małe wyjaśnienie: Przy tworzeniu bazy (pierwsze odpalenie kontenera mysql) dane są zapisane w katalogu Data/database. Tworzona jest czysta baza o podanej nazwie, loginie i haśle. Restart / Wyłączenie / Usunięcie i ponowne utworzenie kontenera nie powoduje utraty danych bazy. Aby usunąć dane, należy opróżnić katalog. Po opróżnieniu katalogu, ponowne uruchomienie kontenera bazodanowego powoduje utworzenie czystej bazy.

– letsencrypt

  • image: interaction/letsencrypt:master – gotowy obraz
  • environment:
    • DOMAINS=api.myfood.love myfood.love – domeny które powinny mieć ssl, dla nich jest generowany certyfikat, nie mogą to być domeny lokalne lub zmapowane w pliku host systemu
    • [email protected] – email który jest zawarty w certyfikacie, powinien to być istniejący adres email
  • expose: – „80” – port na którym nasłuchuje kontener
  • volumes:
    • ./Data/letsencrypt:/etc/letsencrypt – zmapowany katalog z wygenerowanymi certyfikatami
    • ./Logs/letsencrypt:/var/log/letsencrypt – zmapowany katalog gdzie można przejrzeć logi

– haproxy – serwer proxy przez który przechodzi cały ruch z portu 80 i 443 (każda domena i subdomena)

  • image: interaction/haproxy:master
  • links: – kontener musi być podłączony do letsencrypt oraz do wszystkich kontenerów na który ma być kierowany ruch
  • depends_on: – polecenie to sprawia, że haproxy odpalane jest na końcu, oraz że zależy jego działanie od innych kontenerów
  • ports: – „80:80” – „443:443” – cały ruch przechodzi przez ten kontener, potrzebne są do obsługi dwa porty 80 (zwykły ruch http) oraz 443 (ruch https)
  • volumes: – ./Data/letsencrypt:/etc/letsencrypt – haproxy oraz letsencrypt muszą dzielić ten sam katalog, z wygenerowanymi certyfikatami

Kilka spraw:

Ważną kwestią aby haproxy działał z SSL, to współdzielenie katalogu letsencrypt. Kontener letsencrypt przy odpaleniu oraz co 24h sprawdza certyfikat i generuje nową wersje. Gdy haproxy wykryje że pliki w katalogu się zmieniły, uaktualnia certyfikaty u siebie. Nigdy więc nie wygaśnie certyfikat SSL ponieważ jest on generowany co 24h

Dodatkowo można wydzielić haproxy razem z letsencrypt z pliku konfiguracyjnego dockerfile, i utworzyć 2 kontenery globalne.

Dzięki temu, w przyszłości można utworzyć całkiem nowe domeny, z nowymi kontenerami, i dodać ich obsługę w haproxy. Ale przykład podam następnym razem.

Koniec

Jeśli dotarłeś do końca, to podziwiam, i dziękuję. Jeśli uważasz, że można to rozpisać łatwiej, zostaw komentarz, na pewno zaktualizuje w przyszłości tą rozpiskę.

 

Ważne linki:

  • https://github.com/docker/dockercloud-haproxy – czysty haproxy bez SSL (przykład docker-compose >>)
  • https://github.com/ixc/letsencrypt-dockercloud-haproxy – użyty obraz haproxy z SSL ‚let’s encrypt
  • https://letsencrypt.org/ – darmowy certyfikat SSL
  • https://docs.docker.com/compose/compose-file/#dockerfile – opis dockerfile u źródeł

 

1 Comment

Add yours

  1. I have been browsing online more than 4 hours today,
    yet I never found any interesting article like yours. It is pretty worth enough
    for me. Personally, if all site owners and bloggers made good content as you did,
    the internet will be much more useful than ever before.

Dodaj komentarz

Your email address will not be published.

*

© 2017 Marcin Frątczak

Theme by Anders NorenUp ↑

Google Analytics Alternative