Bölüm 3: Dockerfile — Çok Aşamalı Yapı
3.1 Neden Çok Aşamalı Yapılar?
Basit bir Dockerfile, her şeyi (Composer, Node.js, npm, geliştirme bağımlılıkları) tek bir katmanda yükler. Sonuçta oluşan görüntü, gereksiz yere yüzlerce megabayt daha büyük olur ve üretim ortamında bulunmaması gereken yapılandırma araçları nedeniyle güvenlik açıkları barındırabilir.
Çok aşamalı yapılar, yapı ortamını yürütme ortamından ayırarak bu durumu çözer:
• Aşama 1 (builder): Composer, Node.js, npm ve tüm geliştirme araçlarının yüklü olduğu ortam. Üretim PHP bağımlılıklarını yükler ve JavaScript varlıklarını derler.
• Aşama 2 (üretim): Temiz bir Alpine Linux tabanından başlar. Yalnızca Aşama 1’den derlenmiş çıktıyı kopyalar. Yürütme sırasında gereksiz hiçbir şey içermez.
Ölçüt Tek Aşama vs Çok Aşamalı
Görüntü boyutu ~800MB vs ~120MB
Saldırı yüzeyi Yüksek (yapı araçları, geliştirme bağımlılıkları) vs Düşük (yalnızca yürütme)
Yapı önbellekleri Kötü vs Harika (aşamalar bağımsız önbellek oluşturur)
Güvenlik taraması Birçok CVE (güvenlik açığı) ile vs Minimum
3.2 Tam Dockerfile
docker/Dockerfile
# ─────────────────────────────────────────────────────────────────────────
# Aşama 1: builder
# Tüm bağımlılıkları yükler ve varlıkları derler.
# Bu aşama ASLA üretime gönderilmez.
# ─────────────────────────────────────────────────────────────────────────
FROM php:8.3-cli AS builder
# Yapı aşamasında gerekli olan sistem bağımlılıklarını yükle:
# git - Composer bu paketleri GitHub'dan klonlamak için gerekli
# zip/unzip - PHP arşiv işlemleri için gerekli
# libpng-dev, libonig-dev, libxml2-dev - PHP eklentileri için başlık dosyaları
# nodejs, npm - Vite ile JS varlıklarını derlemek için
RUN apt-get update && apt-get install -y \
git curl zip unzip \
libpng-dev libonig-dev libxml2-dev \
nodejs npm \
&& docker-php-ext-install pdo pdo_sqlite mbstring exif pcntl bcmath gd \
&& curl -sS https://getcomposer.org/installer | php \
&& mv composer.phar /usr/local/bin/composer \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Docker katman önbelleklemesini artırmak için öncelikle composer dosyalarını kopyala.
# Eğer composer.json ve composer.lock değişmediyse, Docker önbellek katmanını yeniden kullanır.
COPY composer.json composer.lock ./
RUN composer install \
--no-dev \
--optimize-autoloader \
--no-interaction \
--no-scripts
# Aynı önbellek yararı için package.json'u kopyala
COPY package.json package-lock.json ./
RUN npm ci
# Şimdi uygulama kodunun geri kalanını kopyala
COPY . .
# Tüm kod tabanı mevcut olduğundan Composer betiklerini çalıştır
RUN composer run-script post-autoload-dump --no-interaction 2>/dev/null || true
# JavaScript/CSS varlıklarını derle
RUN npm run build
# ─────────────────────────────────────────────────────────────────────────
# Aşama 2: üretim
# İnce bir Alpine tabanlı görüntü. Yalnızca çalışma koşulları.
# ─────────────────────────────────────────────────────────────────────────
FROM php:8.3-fpm-alpine AS production
# Çalışma ortamı sistem paketlerini yükle:
# nginx - Gelen istekleri kabul edecek HTTP sunucusu
# supervisor - hem nginx hem de php-fpm'yi çalıştıracak süreç yöneticisi
# sqlite - SQLite çalışma kütüphaneleri
RUN apk add --no-cache \
nginx \
supervisor \
sqlite \
&& docker-php-ext-install pdo pdo_sqlite mbstring exif pcntl bcmath
WORKDIR /var/www/html
# Builder aşamasından derlenen uygulamayı kopyala.
# Kritik olarak, node_modules veya geliştirme bağımlılıklarını kopyalamıyoruz.
COPY --from=builder /app /var/www/html
# Konfigürasyon dosyalarını kopyala
COPY docker/nginx.conf /etc/nginx/nginx.conf
COPY docker/php.ini /usr/local/etc/php/conf.d/custom.ini
COPY docker/supervisord.conf /etc/supervisord.conf
# SQLite veritabanı dizinini oluştur.
# Gerçek .sqlite dosyası k8s'de PersistentVolumeClaim üzerinden gelecek.
# Yerel olarak Docker hacmi ile bağlanacak.
RUN mkdir -p /var/www/html/database
# Depolama izinlerini düzelt.
# www-data nginx/php-fpm kullanıcısıdır.
RUN chown -R www-data:www-data \
/var/www/html/storage \
/var/www/html/bootstrap/cache \
/var/www/html/database \
&& chmod -R 775 \
/var/www/html/storage \
/var/www/html/bootstrap/cache \
/var/www/html/database
# Laravel'ı üretim için optimize et
RUN php artisan config:cache \
&& php artisan route:cache \
&& php artisan view:cache
EXPOSE 80
# Supervisord hem nginx hem de php-fpm'yi başlatır
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
3.3 Nginx Yapılandırması
Nginx, konteyner içindeki ön yüz HTTP sunucusu olarak görev yapar. Statik varlıkları (CSS, JS, resimler) diskten doğrudan sunar ve tüm PHP isteklerini PHP-FPM’ye FastCGI üzerinden yönlendirir.
docker/nginx.conf
# Özelleştirme yapmasak bile events bloğunu kullanırız.
# Nginx buna ihtiyaç duyar.
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Loglama — stdout/stderr'ye çıktı verir, böylece kubectl logs çalışır
access_log /dev/stdout;
error_log /dev/stderr warn;
# Temel performans ayarları
sendfile on;
keepalive_timeout 65;
gzip on;
gzip_types text/plain application/json application/javascript text/css;
server {
listen 80;
server_name _;
root /var/www/html/public;
index index.php;
# Laravel'ın try_files deseni:
# 1. Kesin dosyayı ($uri) dene
# 2. Dizini ($uri/) dene
# 3. Sorgu dizisi ile index.php'ye başvur
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# Tüm .php dosyalarını 9000 numaralı portta çalışan PHP-FPM'ye gönder
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_read_timeout 300;
}
# .htaccess ve diğer gizli dosyalara erişimi reddet
location ~ /\.ht {
deny all;
}
# SQLite veritabanı dosyasına doğrudan erişimi reddet
location ~ \.sqlite$ {
deny all;
}
}
}
3.4 PHP Yapılandırması
docker/php.ini
; Laravel API için üretim PHP ayarları
; Bellek sınırı — büyük Eloquent işlemleri için artır
memory_limit = 256M
; Saniyede maksimum yürütme süresi
max_execution_time = 60
; POST gövde boyutu için maksimum (API ile dosya yüklemeleri için)
post_max_size = 20M
upload_max_filesize = 20M
; Yanıt başlıklarından PHP sürümünü gizle (güvenlik)
expose_php = Off
; Yanıt içinde hata görüntülemesini devre dışı bırak; bunun yerine stderr'ye kaydet
display_errors = Off
log_errors = On
error_log = /dev/stderr
; OPcache — derlenmiş bytecode'u önbelleğe alarak PHP'yi önemli ölçüde hızlandırır
opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 0 ; üretimde dosyaları yeniden kontrol etme
opcache.validate_timestamps = 0
3.5 Supervisord Yapılandırması
Kubernetes, her konteynerin tek bir ön plan süreci çalıştırmasını bekler. Hem Nginx hem de PHP-FPM’nin çalışabilmesi için Supervisord’u süreç yöneticisi olarak kullanıyoruz.
docker/supervisord.conf
[supervisord]
; Docker, süreci takip edebilmesi için ön planda çalıştır
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0
[program:php-fpm]
command=/usr/local/sbin/php-fpm --nodaemonize
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:nginx]
command=/usr/sbin/nginx -g "daemon off;"
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
#laravel13 #DEVOPS #Kubernetes #laravelDeployment #fullstackdevelopment
Kaynak: Orijinal Makale


