Aplikacja Symfony w Dockerze
Każdy, kto pracował ze złożonymi projektami, musiał też słyszeć o Dockerze. W skrócie, narzędzie to pozwala ujednolicić oprogramowanie używane w każdym z wielu projektów tak, aby działało w taki sam sposób, niezależnie od maszyny hosta.
Docker zapewnia warstwę abstrakcji, którą nazywamy kontenerami. Kontenery upraszczają deployment oraz wykonanie naszych aplikacji. Dzięki nim możemy zapomnieć o jednym z najczęściej powtarzających się problemów: “U mnie działa”.
Ponieważ w kontenerach pakowane są zależności naszej aplikacji, unikamy potrzeby instalowania ich za każdym razem, gdy zmieniamy nasze stanowisko pracy. W tym artykule nauczymy się integrować Dockera z Symfony tak, aby można go było odpalić na każdym komputerze, czy serwerze. Wystarczy nam tutaj Docker zainstalowany tam, gdzie chcemy uruchomić nasz projekt. Jeżeli nie znasz jeszcze dobrze tego narzędzia, to polecam tę stronę.
Przejdźmy do konkretów.
Struktura folderów
Na początku ustalimy strukturę naszego projektu. Ponieważ używamy Dockera, będzie ona wyglądała następująco:
- w folderze build będziemy mieć pliki, których używamy do konfiguracji każdego z kontenerów Dockera naszej aplikacji.
- database naszego projektu będzie w folderze mysql
- w folderze symfony będziemy mieli aplikację, którą napisze przy użyciu naszego frameworku PHP
- plik
docker-compose.yml
będzie tam, gdzie konfiguracja 3 kontenerów naszej aplikacji: ten od Nginx, ten od PHP i ten od MySQL.
Docker Compose pozwala nam zdefiniować plik z listą wszystkich kontenerów, z której będzie się składać aplikacji i później je odpalić. Konfiguracji tej dokonujemy w pliku YAML w katalogu głównym projektu.
Jeśli chcesz przeczytać więcej, sugeruję zapoznać się z oficjalną dokumentacją Dockera.
Konfiguracja kontenera Nginx
Pierwszą rzeczą, jakiej dokonamy, jest konfiguracja kontenera, w którym znaduje się serwer Nginx. Aby to zrobić, otwieramy docker-compose.yml
i dodajemy:
W czwartej linii kodu zdefiniujemy kontener Nginx:
dockerfile
wskazuje plik konfiguracyjny, który zostanie użyty do zbudowania kontenera, który utworzymy w następnej kolejnościvolumes
stanowi o tym, że nasz lokalny folder o nazwiesymfony
będzie połączony z folderem/var/www/symfony
w kontenerzeports
wykonuje mapowanie między portem 80 kontenera a portem 8001, z którego będziemy korzystać, aby uzyskać dostęp przez przeglądarkęnetworks
ustawia sieć dla całego projektu tak, aby wszystkie kontenery mogły się ze sobą komunikować
Następnie utworzymy plik Dockerfile-nginx
, również w katalogu głównym naszego projektu. z następującą zawartością:
W pierwszej linii kodu zdefiniujemy obraz Nginx, którego chcemy użyć, używając dyrektywy FROM.
Dalej użyjemy metody COPY
, aby skopiować zawartość pliku default.conf
naszego projektu (z domyślną konfiguracją serwera, której użyje Nginx), który znajduje się w folderze /etc/nginx/conf.d
kontenera.
Plik default.conf
zostanie umieszczony w folderze /build/nginx
i będzie wyglądał następująco:
Jak widać, w trzeciej linii mamy konfigurację root
która wskazuje na folder public
naszego projektu.
Ważne: Pamiętaj, że w projekcie Symfony serwer musi wskazywać nie na katalog główny projektu, ale na jego folder public
.
Mając to wszystko, możemy już przetestować nasz pierwszy kontener, wykonując następujące polecenie z katalogu głównego projektu:
docker-compose up -d --build
Kod ten zbuduje jedyny kontener, jaki mamy.
Konfiguracja kontenera dla PHP
Następnym krokiem będzie stworzenie kontenera, w którym będzie działać usługa PHP FPM, dla której dodamy do naszego pliku docker-compose.yml
:
Jak widać, konfiguracja jest podobna do tej, której używamy dla Nginx, z wyjątkiem następujących szczegółów:
- W
environment
możemy zadeklarować zmienne środowiskowe, które chcemy, aby nasz projekt Symfony odczytał i załadował później networks
również składa się z jednego elementusymfony
, który pozwala na komunikację tego kontenera i Nginx.volumes
mają taką samą wartość jak kontener Nginx, więc foldersymfony
naszego projektu jest połączony z folderem/var/www/symfony
kontenera.
Jeśli chodzi o plik Dockerfile-php
, będzie on wyglądał następująco:
Za pomocą polecenia docker-php-ext-install
możemy zainstalować wszystkie potrzebne nam rozszerzenia PHP. W naszym przypadku używam tylko zip
, intl
i tych związanych z MySQL. Pełną listę możesz zobaczyć tutaj.
Ponownie możesz sprawdzić, czy wszystko poszło poprawnie, używając następującego polecenia:
docker-compose up -d --build
Teraz zobaczymy, jak wdrażane są dwa kontenery, Nginx i nowy PHP.
Konfiguracja kontenera dla MySQL
Kontener dla MySQL można skonfigurować, dodając do naszego pliku docker-compose.yml
następujące polecenie:
W tym przypadku nie potrzebujemy pliku dockerfile, ponieważ cała konfiguracja wymagana przez nasz kontener dla MySQL może być określona w pliku YAML. Jest jednak kilka szczegółów do omówienia.
Wtyczka uwierzytelniająca
W 29 linii kodu dodałem konfigurację, która pozwala nam ustalić, która wtyczka uwierzytelniająca będzie używana podczas łączenia się z MySQL. Zrobiłem to, ponieważ do wersji PHP 7.4 nie było zgodności z wtyczką MySQL do uwierzytelniania użytkowników, co powoduje następujący błąd:
PDO::__construct(): The server requested authentication method unknown to the client [caching_sha2_password] (źródło)
Użytkownicy baz danych
W linii 31 ustawiłem hasło użytkownika root
, abyśmy mogli go następnie użyć do uwierzytelnienia w Doctrine.
W przypadku, gdy chcielibyśmy wygenerować bazę danych w momencie tworzenia kontenera wraz z użytkownikiem posiadającym wszystkie uprawnienia, możemy wybrać następującą konfigurację:
Zależności między kontenerami
W linii 25 dodałem zależność od kontenera MySQL do kontenera PHP, aby były one uruchamiane w odpowiedniej kolejności.
Deploy trzech kontenerów
Po zakończeniu konfigurowania kontenera MySQL będziemy mieli wszystko gotowe, więc wykonamy polecenie zbudowania i zdeploy’owania trzech kontenerów:
docker-compose up -d --build
Jeśli wszystko poszło dobrze, zapewne otrzymasz wynik podobny do następującego:
symfony-docker_nginx_1 is up-to-date
symfony-docker_php_1 is up-to-date
Creating symfony-docker_mysql_1 ... done
Instalacja Symfony
Ponieważ od teraz będziemy pracować z naszymi kontenerami, instalacja Symfony będzie się odbywać w nich, a nie w naszym systemie operacyjnym.
Dlatego pierwszą rzeczą, którą będziemy musieli zrobić, jest udzielenie dostępu do naszego kontenera, w którym znajduje się PHP (pamiętaj, aby go pobrać) za pomocą polecenia:
docker exec -it symfony-docker_php_1 bash
gdzie symfony-docker_php_1
to nazwa, którą polecenie docker-compose up
zwróciło po zakończeniu uruchamiania kontenerów.
Teraz w kontenerze możemy zainstalować Symfony, tak jak podpowiada dokumentacja:
curl -sS https://get.symfony.com/cli/installer | bash
mv /root/.symfony/bin/symfony /usr/local/bin/symfony
symfony new symfony --dir=/var/www/symfony
Ważne: Możliwe, że przy tworzeniu projektu wystąpi następujący błąd:
*** Please tell me who you are.
Run
git config --global user.email "[email protected]"
git config --global user.name "Your Name"
to set your account's default identity
Dodanie żądanej konfiguracji Git rozwiąże ten problem.
Po zainstalowaniu Symfony możemy sprawdzić, czy wszystko zadziałało poprawnie, uzyskując dostęp do localhost: 8001 (to port, który mapujemy w Nginx w pliku docker-compose.yml
), który pokaże nam stronę powitalną Symfony:
Jeśli teraz chcemy używać Doctrine do pracy z bazą danych, wystarczy zainstalować odpowiedni pakiet za pomocą composer / flex (zawsze z naszego kontenera):
composer require symfony/orm-pack
composer require --dev symfony/maker-bundle
Dodaj zmienną środowiskową DATABASE_URL
do konfiguracji kontenera PHP:
DATABASE_URL: mysql://symfony_user:symfony_password@mysql:3306/symfony_db?serverVersion=5.7
Hostem bazy danych jest nazwa naszego kontenera (mysql:3306
), a nie adres IP 127.0.0.1. Oznacza to, że jeśli np. nasz kontener ma nazwę database
w naszym pliku docker-compose.yml
, zmienna środowiskowa służąca do połączenia z tą bazą danych miałaby wartość:
DATABASE_URL: mysql://symfony_user:symfony_password@database:3306/symfony_db?serverVersion=5.7
Następnie zrestartujemy kontener, aby nanieść tę zmianę w zmiennych środowiskowych PHP:
docker-compose up -d php
Teraz możemy spokojnie pracować z naszą bazą danych. Np. w naszym kontenerze PHP możemy uruchomić polecenie:
bin/console doctrine:database:create
jeśli chcemy sprawdzić, czy projekt poprawnie łączy się z bazą danych, którą zdefiniowaliśmy.
Repozytorium
Jeśli chcesz uzyskać dostęp do pełnego kodu, znajdziesz go tutaj.
Podsumowanie
Po zdokeryzowaniu projektu możemy pracować z nim na dowolnej maszynie, nie martwiąc się o zależności czy używany system operacyjny.
To bardzo pomocne dla średnich i dużych projektów, w które zaangażowanych jest większa liczba programistów, ponieważ wszyscy będą pracować na tych samych wersjach. To zaś zapobiegnie błędom korzystania z różnych wersji w bibliotekach, których potrzebujemy.
Dodatkowo wystarczy zainstalować Dockera na maszynie, na której chcemy pracować, aby móc dalej rozwijać projekt bez konieczności instalowania po kolei niezbędnych bibliotek.
Oryginał tekstu w języku angielskim przeczytasz tutaj.