🚀 Docker dla Laravel: Przewodnik dla początkujących

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

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:

  1. 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
    
  2. Wprowadź zmiany w kodzie: Edytuj pliki Laravel jak zwykle w swoim IDE

  3. Uruchom migracje po zmianach w bazie danych:

    make migrate
    
  4. Uruchom kompilację zasobów frontendowych:

    make vite
    
  5. Testuj pocztę używając MailHog:

    • Wywołaj email w swojej aplikacji
    • Zobacz go pod adresem http://localhost:8025
Komentarze (0)
Zostaw komentarz

© 2025 Wszelkie prawa zastrzeżone.