Czy masz dość problemu "u mnie działa"? Szukasz sposobu na usprawnienie środowiska deweloperskiego Laravel? Docker jest odpowiedzią, a ten przewodnik przeprowadzi Cię przez proces konfiguracji potężnego, spójnego środowiska deweloperskiego dla Twoich projektów Laravel.
📋 Spis treści
- Wprowadzenie do Dockera
- Dlaczego Docker dla Laravel?
- Rozpoczęcie pracy
- Struktura projektu
- Konfiguracja Dockera
- Optymalizacja wydajności
- Używanie Makefile
- Narzędzia deweloperskie
- Rozwiązywanie problemów
- Najlepsze praktyki
- Podsumowanie
- Kod źródłowy
- Słownik
Wprowadzenie do Dockera
Zanim przejdziemy do konfiguracji Laravel, zrozumiemy czym jest Docker i dlaczego jest rewolucyjny dla rozwoju oprogramowania.
Docker to platforma, która umożliwia programistom pakowanie aplikacji i ich zależności w ustandaryzowane jednostki zwane kontenerami. Te kontenery są lekkimi, samodzielnymi i wykonywalnymi pakietami, które zawierają wszystko, co jest potrzebne do uruchomienia aplikacji: kod, środowisko wykonawcze, narzędzia systemowe, biblioteki i ustawienia.
Kluczowe koncepcje Dockera:
- Kontener: Lekki, samodzielny, wykonywalny pakiet zawierający wszystko potrzebne do uruchomienia oprogramowania
- Obraz: Szablon dla kontenera (jak klasa w programowaniu)
- Dockerfile: Skrypt zawierający instrukcje do budowania obrazu Dockera
- Docker Compose: Narzędzie do definiowania i uruchamiania wielokontenerowych aplikacji Dockera
- Wolumen: Mechanizm trwałego przechowywania danych istniejący poza kontenerami
- Sieć: System komunikacji umożliwiający kontenerom wzajemną komunikację
Dlaczego Docker dla Laravel?
Docker zrewolucjonizował sposób, w jaki tworzymy i wdrażamy aplikacje. Dla projektów Laravel zapewnia:
- Spójne środowiska: Koniec z problemem "u mnie działa"
- Łatwe wprowadzanie: Nowi członkowie zespołu mogą rozpocząć pracę w minutach, nie dniach
- Środowisko podobne do produkcyjnego: Rozwijaj w środowisku odzwierciedlającym produkcję
- Izolowane usługi: Trzymaj swoje usługi PHP, Nginx, MySQL i Redis oddzielone i łatwe w zarządzaniu
- Kontrola wersji środowisk: Śledź zmiany w środowisku wraz z kodem
- Brak konfliktów lokalnych zależności: Każdy projekt może używać różnych wersji PHP, MySQL itp. bez konfliktów
Rozpoczęcie pracy
Tworzenie nowego projektu Laravel z Dockerem
Możesz utworzyć nowy projekt Laravel lub użyć Dockera z istniejącym. Dla nowego projektu:
# Sklonuj przykładowe repozytorium
git clone https://github.com/Dommmin/laravel-docker.git my-project
cd my-project
Struktura projektu
Nasza konfiguracja Dockera podąża za podejściem modułowym, trzymając konfigurację Dockera oddzielnie od kodu aplikacji:
project/
├── docker/ # Pliki konfiguracyjne Dockera
│ ├── php/ # Konfiguracja PHP
│ │ ├── Dockerfile # Instrukcje budowania obrazu PHP
│ │ ├── php.ini # Ustawienia PHP
│ │ └── www.conf # Ustawienia PHP-FPM
│ ├── nginx/ # Konfiguracja Nginx
│ │ └── conf.d/ # Bloki serwera
│ └── supervisord.conf # Konfiguracja menedżera procesów
├── docker-compose.yml # Definicja wielokontenerowa
├── Makefile # Komendy pomocnicze
└── .env # Zmienne środowiskowe
Konfiguracja Dockera
Bazowy obraz PHP
Używamy niestandardowego obrazu PHP 8.4 FPM hostowanego na Docker Hub (dommin/php-8.4-fpm
). Ten obraz jest wstępnie skonfigurowany z:
- Optymalizacją PHP-FPM
- Typowymi rozszerzeniami PHP
- Composer
- Node.js i npm
- Git
Uwaga: W następnym artykule zbadamy, jak tworzyć i optymalizować własne obrazy Dockera dla aplikacji PHP, w tym używanie obrazów opartych na Alpine dla produkcji, aby znacząco zmniejszyć rozmiar obrazu.
Wyjaśnienie Dockerfile
Poniżej znajduje się nasz Dockerfile
z komentarzami wyjaśniającymi każdą linię:
# Użyj naszego niestandardowego obrazu PHP 8.4 FPM jako bazy
FROM dommin/php-8.4-fpm:latest
# Skopiuj nasze niestandardowe pliki konfiguracyjne PHP i PHP-FPM
COPY docker/php/php.ini /usr/local/etc/php/conf.d/custom.ini
COPY docker/php/www.conf /usr/local/etc/php-fpm.d/www.conf
COPY docker/start.sh /usr/local/bin/start.sh
COPY ./docker/supervisord.conf /etc/supervisor/supervisord.conf
# Przełącz na użytkownika root do wykonywania operacji uprzywilejowanych
USER root
# Pozwól na dostosowanie ID użytkownika/grupy dla lepszej kompatybilności z systemem plików hosta
ARG USER_ID=1000
ARG GROUP_ID=1000
# Zaktualizuj użytkownika www-data, aby pasował do UID/GID użytkownika hosta
RUN usermod -u ${USER_ID} www-data && groupmod -g ${GROUP_ID} www-data
# Nadaj uprawnienia wykonywania skryptowi startowemu
RUN chmod +x /usr/local/bin/start.sh
# Utwórz niezbędne katalogi dla Supervisora
RUN mkdir -p /var/log/supervisor /var/run/supervisor
# Ustaw odpowiednie uprawnienia dla katalogów
RUN chown -R www-data:www-data /var/www /var/log/supervisor /var/run/supervisor
# Utwórz katalog logów dla Supervisora
RUN mkdir -p /var/log/supervisor
RUN chown -R www-data:www-data /var/log/supervisor
# Przełącz z powrotem na użytkownika nie-root dla bezpieczeństwa
USER www-data
Wyjaśnienie usług Docker Compose
Nasz docker-compose.yml
tworzy kompletne środowisko deweloperskie z wieloma połączonymi usługami. Przeanalizujmy każdą usługę i jej konfigurację:
Usługa App (Aplikacja PHP)
app:
build:
context: . # Użyj bieżącego katalogu jako kontekstu budowania
dockerfile: docker/php/Dockerfile
args:
# Przekaż ID użytkownika/grupy hosta, aby uniknąć problemów z uprawnieniami
- USER_ID=${USER_ID:-1000}
- GROUP_ID=${GROUP_ID:-1000}
container_name: ${COMPOSE_PROJECT_NAME}_app
command: ["sh", "-c", "/usr/local/bin/start.sh"]
restart: unless-stopped
working_dir: /var/www
volumes:
- ./:/var/www # Zamontuj katalog projektu do kontenera
- ./docker/php/php.ini:/usr/local/etc/php/conf.d/custom.ini
- ./docker/php/www.conf:/usr/local/etc/php-fpm.d/www.conf
- ./docker/supervisord.conf:/etc/supervisor/supervisord.conf
- .env:/var/www/.env
networks:
- laravel-network
ports:
- "5173:5173" # Port serwera deweloperskiego Vite
- "9000:9000" # Port PHP-FPM
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
Kluczowe punkty dotyczące usługi app:
- Używa niestandardowego Dockerfile do budowania środowiska PHP
- Montuje cały katalog projektu dla natychmiastowych aktualizacji kodu
- Udostępnia port 9000 dla PHP-FPM i 5173 dla Vite
- Zależy od stanu zdrowia MySQL i Redis przed uruchomieniem
- Używa supervisora do zarządzania wieloma procesami (PHP-FPM, Horizon, Vite)
Usługa Nginx
nginx:
image: nginx:alpine
container_name: ${COMPOSE_PROJECT_NAME}_nginx
restart: unless-stopped
ports:
- "80:80"
volumes:
- ./:/var/www
- ./docker/nginx/conf.d:/etc/nginx/conf.d
depends_on:
- app
networks:
- laravel-network
Kluczowe punkty dotyczące usługi nginx:
- Używa lekkiego obrazu Nginx opartego na Alpine
- Mapuje port 80 dla dostępu do sieci
- Montuje niestandardową konfigurację Nginx
- Zależy od usługi app do przetwarzania PHP
Usługa MySQL
mysql:
image: mysql:8.0
container_name: ${COMPOSE_PROJECT_NAME}_mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_DATABASE_TEST: laravel_test
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
healthcheck:
test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]
interval: 10s
timeout: 5s
retries: 5
start_period: 60s
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
networks:
- laravel-network
Kluczowe punkty dotyczące usługi MySQL:
- Używa MySQL 8.0 z obsługą UTF-8
- Implementuje sprawdzanie stanu zdrowia dla orkiestracji kontenerów
- Przechowuje dane używając nazwanego wolumenu
- Udostępnia port 3306 dla połączeń z bazą danych
Usługa Redis
redis:
image: redis:alpine
container_name: ${COMPOSE_PROJECT_NAME}_redis
restart: unless-stopped
healthcheck:
test: [ "CMD", "redis-cli", "ping" ]
interval: 10s
timeout: 5s
retries: 5
start_period: 60s
ports:
- "6379:6379"
networks:
- laravel-network
Kluczowe punkty dotyczące usługi Redis:
- Używa obrazu Redis opartego na Alpine dla mniejszego rozmiaru
- Implementuje sprawdzanie stanu zdrowia
- Udostępnia port 6379 dla połączeń Redis
Usługa MailHog
mailhog:
image: mailhog/mailhog:latest
container_name: ${COMPOSE_PROJECT_NAME}_mailhog
restart: unless-stopped
ports:
- "1025:1025" # Port SMTP
- "8025:8025" # Port interfejsu webowego
volumes:
- mailhog_data:/maildir
networks:
- laravel-network
Kluczowe punkty dotyczące usługi MailHog:
- Zapewnia środowisko testowe dla poczty
- Udostępnia porty SMTP i interfejsu webowego
- Przechowuje emaile używając nazwanego wolumenu
Konfiguracja Nginx
Konfiguracja Nginx w docker/nginx/conf.d/default.conf
jest zoptymalizowana dla aplikacji Laravel. Przeanalizujmy kluczowe sekcje:
Podstawowa konfiguracja serwera
server {
listen 80;
listen [::]:80;
server_name localhost;
root /var/www/public;
index index.php;
# Konfiguracja logowania
access_log /var/www/storage/logs/nginx_access.log;
error_log /var/www/storage/logs/nginx_error.log;
charset utf-8;
client_max_body_size 100M;
client_body_buffer_size 128k;
}
Ta sekcja konfiguruje:
- Serwer HTTP nasłuchujący na porcie 80
- Katalog główny wskazujący na katalog public Laravel
- Konfigurację logowania dla logów dostępu i błędów
- Kodowanie znaków UTF-8
- Limity rozmiaru przesyłanych plików
Buforowanie plików statycznych
# Buforowanie plików statycznych
location ~* \.(?:ico|css|js|gif|jpe?g|png|woff2?|eot|ttf|svg|otf)$ {
expires 1y;
access_log off;
add_header Cache-Control "public, no-transform";
add_header X-Content-Type-Options "nosniff";
try_files $uri =404;
}
Ta konfiguracja:
- Buforuje zasoby statyczne przez rok
- Wyłącza logowanie dostępu dla plików statycznych
- Dodaje nagłówki bezpieczeństwa
- Implementuje prawidłową obsługę typów MIME
Przetwarzanie PHP
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_param PATH_INFO $fastcgi_path_info;
# Ustawienia buforowania PHP-FPM
fastcgi_cache_use_stale error timeout http_500 http_503;
fastcgi_cache_valid 200 60m;
fastcgi_cache_bypass $http_pragma;
fastcgi_cache_revalidate on;
}
Ta sekcja:
- Konfiguruje przetwarzanie PHP-FPM
- Ustawia buforowanie FastCGI
- Obsługuje wykonywanie plików PHP
- Implementuje prawidłową obsługę ścieżek
Kompresja Gzip
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript;
gzip_vary on;
gzip_comp_level 6;
gzip_min_length 1000;
gzip_proxied any;
To włącza:
- Kompresję Gzip dla różnych typów plików
- Optymalizację poziomu kompresji
- Minimalny rozmiar pliku do kompresji
- Prawidłową obsługę nagłówków
Konfiguracja PHP-FPM
Konfiguracja PHP-FPM w docker/php/www.conf
jest zoptymalizowana pod kątem wydajności i bezpieczeństwa. Przeanalizujmy kluczowe ustawienia:
Ustawienia menedżera procesów
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500
Te ustawienia:
- Używają dynamicznego zarządzania procesami
- Ograniczają maksymalną liczbę procesów potomnych do 50
- Uruchamiają 5 procesów serwera
- Utrzymują 5-10 zapasowych serwerów
- Restartują procesy po 500 żądaniach, aby zapobiec wyciekom pamięci
Limity czasowe i logowanie
pm.process_idle_timeout = 10s
request_terminate_timeout = 30s
request_slowlog_timeout = 5s
slowlog = /proc/self/fd/2
php_admin_value[error_log] = /proc/self/fd/2
php_admin_flag[log_errors] = on
Ta konfiguracja:
- Ustawia limit czasu bezczynności procesu na 10 sekund
- Kończy żądania po 30 sekundach
- Loguje wolne żądania (ponad 5 sekund)
- Konfiguruje logowanie błędów do stdout
Ustawienia bezpieczeństwa
php_admin_value[memory_limit] = 256M
php_admin_value[disable_functions] = "exec,passthru,shell_exec,system"
Te ustawienia:
- Ograniczają użycie pamięci PHP do 256MB
- Wyłączają niebezpieczne funkcje PHP
- Zwiększają bezpieczeństwo kontenera
Optymalizacja wydajności
Konfiguracja PHP-FPM
- Ustawienia menedżera procesów: Zoptymalizowane ustawienia
pm
dla lepszego wykorzystania zasobów - Konfiguracja workerów: Odpowiednie ustawienia dla liczby workerów i żądań na workera
- Limity pamięci: Dostosowane do potrzeb deweloperskich
Konfiguracja Supervisora dla workerów kolejki
[supervisord]
nodaemon=true # Uruchom na pierwszym planie
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisor/supervisord.pid
user=www-data # Uruchom jako użytkownik nie-root
[program:horizon] # Menedżer kolejki Laravel Horizon
process_name=%(program_name)s
command=php /var/www/artisan horizon
autostart=true # Uruchom automatycznie
autorestart=true # Uruchom ponownie, jeśli się zawiesi
redirect_stderr=true
stdout_logfile=/var/log/supervisor/horizon.log
stopwaitsecs=3600 # Poczekaj na zakończenie zadań przy zatrzymaniu
user=www-data
Optymalizacja Nginx
- Kompresja Gzip: Zmniejsza rozmiar odpowiedzi
- Buforowanie FastCGI: Poprawia wydajność dla powtarzających się żądań
- Obsługa plików statycznych: Zoptymalizowana dla zasobów
- Nagłówki bezpieczeństwa: Dodaje ochronę przed typowymi podatnościami
Używanie Makefile dla uproszczenia
Jednym z najpotężniejszych dodatków do naszej konfiguracji Dockera jest Makefile
. Ten plik zapewnia proste komendy, które abstrahują złożone operacje Dockera, ułatwiając deweloperom pracę ze środowiskiem.
Czym jest Makefile?
Makefile to plik konfiguracyjny używany przez narzędzie make
. Definiuje zestaw zadań do wykonania, gdy uruchomisz komendę make
z określonym celem.
Korzyści z używania Make z Dockerem
- Uproszczone komendy: Zamiast wpisywać długie komendy docker-compose, używaj krótkich aliasów
- Ustandaryzowane przepływy pracy: Każdy w zespole używa tych samych komend
- Dokumentacja: Sam Makefile służy jako dokumentacja dla typowych operacji
- Automatyzacja: Łańcuchuj wiele komend w jednym celu make
Nasz Makefile dla Dockera
.PHONY: up down build install migrate fresh test setup-test-db
# Uruchom aplikację
up:
docker compose up -d
# Zatrzymaj aplikację
down:
docker compose down
# Zbuduj kontenery
build:
@echo "Konfigurowanie projektu..."
@if [ ! -f .env ]; then \
cp .env.local .env; \
echo "Utworzono plik .env z .env.local"; \
fi
docker compose build
# Zainstaluj zależności
install:
docker compose exec app composer install
docker compose exec app npm install
# Uruchom migracje
migrate:
docker compose exec app php artisan migrate
# Świeże migracje
fresh:
docker compose exec app php artisan migrate:fresh
# Konfiguracja bazy testowej
setup-test-db:
docker compose exec mysql mysql -uroot -psecret -e "CREATE DATABASE IF NOT EXISTS laravel_test;"
docker compose exec app php artisan migrate --env=testing
# Uruchom testy
test: setup-test-db
docker compose exec app php artisan test --env=testing
# Konfiguracja projektu od podstaw
setup: build up
docker compose exec app composer install
docker compose exec app npm install
docker compose exec app php artisan key:generate
docker compose exec app php artisan migrate
@echo "Konfiguracja projektu zakończona!"
# Pokaż logi
logs:
docker compose logs -f
# Wejdź do kontenera app
shell:
docker compose exec app bash
# Wyczyść wszystkie cache
clear:
docker compose exec app php artisan cache:clear
docker compose exec app php artisan config:clear
docker compose exec app php artisan route:clear
docker compose exec app php artisan view:clear
# Uruchom serwer deweloperski Vite
vite:
docker compose exec app npm run dev
Używanie Makefile
Z naszym Makefile, konfiguracja nowego projektu jest tak prosta jak:
# Skonfiguruj cały projekt jedną komendą
make setup
# Uruchom środowisko deweloperskie
make up
# Uruchom migracje bazy danych
make migrate
# Uzyskaj dostęp do powłoki kontenera app
make shell
# Uruchom serwer deweloperski Vite
make vite
To drastycznie upraszcza wprowadzanie nowych deweloperów. Nowi członkowie zespołu mogą uzyskać w pełni funkcjonalne środowisko za pomocą zaledwie kilku komend!
Narzędzia deweloperskie
Testowanie URL-i
- Główna aplikacja:
http://localhost
- Interfejs MailHog:
http://localhost:8025
(do testowania poczty) - Monitorowanie kolejki:
http://localhost/horizon
(jeśli zainstalowano Horizon)
Przykład przepływu pracy
Oto typowy przepływ pracy używając naszej konfiguracji Dockera:
-
Sklonuj projekt i uruchom kontenery:
git clone https://github.com/your-username/your-project.git cd your-project make setup # Buduje kontenery, instaluje zależności, uruchamia migracje
-
Wprowadź zmiany w kodzie: Edytuj pliki Laravel jak zwykle w swoim IDE
-
Uruchom migracje po zmianach w bazie danych:
make migrate
-
Uruchom kompilację zasobów frontendowych:
make vite
-
Testuj pocztę używając MailHog:
- Wywołaj email w swojej aplikacji
- Zobacz go pod adresem
http://localhost:8025