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
pmdla 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