Docker Ortamında Composer ile Yerel Paket Geliştirme İpuçları
Modern PHP projelerinde Docker ve Composer, geliştirme ortamı tutarlılığı ve bağımlılık yönetimi için vazgeçilmezdir. Ancak, ana proje içinde yerel Composer paketi geliştirirken bu ikiliyi verimli kullanmak bazen zorlayıcı olabilir. Bu makale, Docker ortamında Composer ile yerel paket geliştirirken karşılaşabileceğiniz zorlukları aşmanıza yardımcı olacak pratik ipuçları, en iyi uygulamalar ve detaylı yapılandırma örnekleri sunarak geliştirme sürecinizi hızlandırmayı hedeflemektedir.
Docker ve Composer Ortamını Hazırlama
Yerel paket geliştirme sürecine başlamadan önce, projenizin ve geliştirilecek paketin ihtiyaç duyduğu temel Docker ve Composer ortamını doğru bir şekilde yapılandırmak kritik öneme sahiptir. Bu adım, ilerleyen süreçlerde yaşanabilecek uyumluluk ve bağımlılık sorunlarının önüne geçer.
docker-compose.yml Dosyası Yapılandırması
docker-compose.yml dosyası, uygulamanızın servislerini, ağlarını ve depolama birimlerini tanımladığınız merkezi bir yapılandırma dosyasıdır. Yerel paket geliştirme için, hem ana projenizi hem de geliştirilecek paketinizi Docker konteynerleri içinde erişilebilir kılmanız gerekir. Özellikle volume bağlama (mounting) işlemleri, yerel değişikliklerinizin anında konteyner içinde yansımasını sağlar.
Aşağıda temel bir PHP-FPM ve Nginx servislerini içeren docker-compose.yml örneği bulunmaktadır:
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
volumes:
- .:/var/www/html # Ana projenin bağlanması
- ./packages/my-local-package:/var/www/html/vendor/my-vendor/my-local-package # Yerel paketin bağlanması
working_dir: /var/www/html
environment:
XDEBUG_MODE: develop,debug
XDEBUG_CONFIG: client_host=host.docker.internal
nginx:
image: nginx:stable-alpine
ports:
- "80:80"
volumes:
- .:/var/www/html
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app
Bu örnekte, app servisi altında hem ana projenin kök dizini (.:/var/www/html) hem de geliştirilmekte olan yerel paketin dizini (./packages/my-local-package:/var/www/html/vendor/my-vendor/my-local-package) bağlanmıştır. Bu sayede, yerel pakette yaptığınız her değişiklik anında Docker konteyneri içinde görünür olacaktır.
PHP Geliştirme Ortamı İçin Dockerfile
PHP servisiniz için özel bir Dockerfile oluşturmak, gerekli PHP uzantılarını, Composer'ı ve diğer geliştirme araçlarını kurmanızı sağlar. Bu, ortamınızın özelleştirilebilir ve tekrarlanabilir olmasını garantiler.
FROM php:8.2-fpm-alpine
# Gerekli bağımlılıkları yükle
RUN apk add --no-cache \
git \
zip \
unzip \
icu-dev \
libpq-dev \
# Diğer ihtiyacınız olan paketler...
&& docker-php-ext-install pdo pdo_pgsql intl opcache \
# Xdebug kurulumu (isteğe bağlı)
&& pecl install xdebug \
&& docker-php-ext-enable xdebug
# Composer kurulumu
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
WORKDIR /var/www/html
CMD ["php-fpm"]
Bu Dockerfile, PHP 8.2 FPM Alpine tabanlı bir imaj kullanır, gerekli sistem bağımlılıklarını ve PHP uzantılarını kurar. Ayrıca, Composer'ı ayrı bir Composer imajından kopyalayarak en güncel sürümünü kullanmanızı sağlar. Xdebug kurulumu, hata ayıklama için önemlidir.
Composer Kurulumu ve Kullanımı
Composer, PHP bağımlılık yöneticisidir. Docker konteyneri içinde Composer'ı kullanmak, ana projenizin ve yerel paketinizin bağımlılıklarını yönetmek için esastır. Dockerfile içinde Composer'ı kurduktan sonra, konteyner içinden veya docker-compose exec komutu ile kolayca kullanabilirsiniz:
# Konteyner içinden Composer çalıştırma
docker-compose exec app composer install
# Konteyner içinden Composer update çalıştırma
docker-compose exec app composer update
Yerel Paket Geliştirme İş Akışı ve Senaryoları
Yerel bir Composer paketi geliştirirken, ana projenizin bu paketi nasıl tanıyacağı ve kullanacağı önemlidir. Composer'ın path repository özelliği ve sembolik bağlantılar bu konuda en sık kullanılan yöntemlerdir.
path Repositories Kullanımı
Composer'ın path repository özelliği, henüz packagist.org gibi bir depoya yüklenmemiş veya üzerinde aktif olarak çalıştığınız yerel paketleri ana projenize dahil etmenizi sağlar. Bu, geliştirme aşamasında paketinizi sürekli olarak yayınlamak zorunda kalmadan test etmenize olanak tanır.
Ana projenizin composer.json dosyasına aşağıdaki gibi bir repositories bölümü eklemeniz gerekir:
{
"name": "my-vendor/main-project",
"description": "Ana projem",
"type": "project",
"require": {
"php": "^8.2",
"my-vendor/my-local-package": "@dev"
},
"repositories": [
{
"type": "path",
"url": "./packages/my-local-package",
"options": {
"symlink": true
}
}
],
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"minimum-stability": "dev",
"prefer-stable": true
}
Burada type: "path" ile Composer'a yerel bir dizini paket deposu olarak kullanmasını söylüyoruz. url değeri, ana projenizin kök dizinine göre paketin bulunduğu yolu belirtir. options.symlink: true ise Composer'ın paketi kopyalamak yerine sembolik bir bağlantı oluşturmasını sağlar, bu da değişikliklerinizin anında yansımasını garantiler.
Sembolik Bağlantılar (Symlinks) ile Çalışma
Yukarıdaki path repository örneğinde de görüldüğü gibi, symlink: true seçeneği, Composer'ın vendor dizini içinde yerel paketinize bir sembolik bağlantı oluşturmasını sağlar. Bu, paketin kaynak kodunda yaptığınız her değişikliğin, ana projenin vendor dizinindeki bağlantı aracılığıyla anında erişilebilir olduğu anlamına gelir. Bu yöntem, geliştirme döngüsünü inanılmaz derecede hızlandırır.
Dikkat: Windows üzerinde Docker Desktop kullanıyorsanız ve WSL2 entegrasyonu yoksa, sembolik bağlantılar bazen sorun çıkarabilir. Bu durumda symlink: false kullanmanız gerekebilir, ancak bu paketin kopyalanmasına neden olacağı için her değişiklikte composer update çalıştırmanız gerekebilir. WSL2 kullanmak bu sorunu genellikle çözer.
Paket Güncellemeleri ve Senkronizasyon
Yerel pakette bir değişiklik yaptığınızda, eğer symlink: true kullanıyorsanız, ana projenin konteynerinde herhangi bir ek işlem yapmanıza gerek kalmaz; değişiklikler anında yansır. Ancak, paketin composer.json dosyasında bir bağımlılık ekler veya değiştirirseniz, ana projenin vendor dizinini güncellemek için docker-compose exec app composer update my-vendor/my-local-package komutunu çalıştırmanız gerekebilir.
Bağımlılık Yönetimi ve Composer Ayarları
Ana proje ile geliştirilen yerel paket arasındaki bağımlılık ilişkilerini doğru yönetmek, karmaşıklığı azaltır ve tutarlı bir geliştirme ortamı sağlar.
Ana Proje ve Geliştirilen Paket Arasındaki İlişki
Ana projeniz, geliştirilen yerel paketinize bir bağımlılık olarak ihtiyaç duyar. Bu bağımlılığı, ana projenin composer.json dosyasındaki require bölümünde belirtmelisiniz. Genellikle, geliştirme aşamasında "@dev" veya belirli bir dev branch'i ("dev-main") kullanmak yaygın bir yaklaşımdır.
{
"require": {
"my-vendor/my-local-package": "@dev"
}
}
Bu, Composer'a my-vendor/my-local-package paketinin en güncel geliştirme sürümünü kullanmasını söyler.
composer.json Dosyasında Geliştirme Bağımlılıkları
Yerel paketinizin de kendi bağımlılıkları olabilir. Bu bağımlılıkları paketin kendi composer.json dosyasında tanımlamalısınız. Eğer bu bağımlılıklar sadece geliştirme veya test aşamasında kullanılıyorsa, require-dev bölümüne eklenmelidir.
// packages/my-local-package/composer.json
{
"name": "my-vendor/my-local-package",
"description": "Yerel olarak geliştirilen paketim",
"require": {
"php": "^8.2",
"monolog/monolog": "^2.0"
},
"require-dev": {
"phpunit/phpunit": "^9.5"
},
"autoload": {
"psr-4": {
"MyVendor\\MyLocalPackage\\": "src/"
}
}
}
Ana projenizin composer install veya composer update komutunu çalıştırdığında, Composer önce ana projenin bağımlılıklarını çözer, ardından path repository üzerinden yerel paketinizi bulur ve onun bağımlılıklarını da yükler.
composer install ve composer update Stratejileri
* İlk Kurulum: Projeyi ilk kez kurarken veya composer.lock dosyasını temel alarak bağımlılıkları yüklerken docker-compose exec app composer install komutunu kullanın. Bu, path repository'nizi de doğru şekilde kuracaktır.
* Bağımlılık Güncelleme: Eğer ana projenin veya yerel paketin composer.json dosyasında bir bağımlılık eklediyseniz, değiştirdiyseniz veya kaldırdıysanız, docker-compose exec app composer update komutunu çalıştırmanız gerekir. Belirli bir paketi güncellemek için docker-compose exec app composer update my-vendor/my-local-package kullanabilirsiniz.
Performans Optimizasyonu ve Geliştirme Deneyimi
Docker ile yerel geliştirme yaparken performans, özellikle dosya sistemi işlemleri ve PHP'nin çalışma hızı açısından önemli bir konudur.
Docker Volume Performansı
Docker'ın varsayılan bind mount'ları (yerel dosya sisteminizden konteynere dosya bağlama), özellikle macOS ve Windows'ta performansı düşürebilir. Bunun nedeni, Docker'ın dosya sistemi işlemlerini sanal makine (VM) ve ana bilgisayar arasında senkronize etme şeklidir.
* Linux: Genellikle iyi performans sunar.
* macOS/Windows (WSL2 olmadan): Performans sorunları yaşanabilir. cached veya delegated mount seçeneklerini denemek faydalı olabilir, ancak bunlar dosya sistemi senkronizasyonunda gecikmelere neden olabilir.
* Windows (WSL2 ile): WSL2, Linux çekirdeği kullandığı için Linux'a yakın bir performans sunar ve genellikle en iyi deneyimi sağlar. Projenizi WSL2 içindeki bir Linux dosya sistemine yerleştirmek, performansı önemli ölçüde artırır.
# docker-compose.yml içinde volume ayarı
services:
app:
volumes:
- .:/var/www/html:cached # macOS/Windows için performans artışı sağlayabilir
Caching Mekanizmaları
Composer'ın kendi cache mekanizması vardır. Dockerfile'ınızda veya docker-compose.yml dosyanızda Composer cache dizinini kalıcı bir Docker volume'a bağlamak, bağımlılıkların her yeniden oluşturmada indirilmesini önler ve composer install/update sürelerini kısaltır.
# docker-compose.yml
services:
app:
volumes:
- .:/var/www/html
- composer-cache:/root/.composer/cache # Composer cache'i kalıcı hale getir
volumes:
composer-cache:
Xdebug Entegrasyonu
Xdebug, PHP uygulamalarınızda hata ayıklamak için vazgeçilmez bir araçtır. Docker ortamında Xdebug'ı doğru yapılandırmak, geliştirme sürecini büyük ölçüde kolaylaştırır.
Dockerfile'ınızda Xdebug'ı kurduktan sonra (yukarıdaki Dockerfile örneğinde gösterildiği gibi), docker-compose.yml dosyanızda Xdebug'ın doğru çalışması için ortam değişkenlerini ayarlamanız gerekir:
# docker-compose.yml
services:
app:
environment:
XDEBUG_MODE: develop,debug # Hata ayıklama ve geliştirme modlarını etkinleştir
XDEBUG_CONFIG: client_host=host.docker.internal # IDE'nizin çalıştığı ana bilgisayarın IP'si
client_host=host.docker.internal ifadesi, Docker Desktop'ın ana bilgisayarı otomatik olarak tanımasını sağlar. Eğer Linux kullanıyorsanız, ana bilgisayarınızın IP adresini manuel olarak bulup (ip a komutu ile) ayarlamanız gerekebilir. IDE'nizde (VS Code, PhpStorm vb.) Xdebug dinleyicisini etkinleştirmeyi unutmayın.
Hata Ayıklama (Debugging) ve Sorun Giderme
Geliştirme sürecinde hatalarla karşılaşmak kaçınılmazdır. Docker ortamında bu hataları etkili bir şekilde ayıklamak, zaman kazandırır.
Docker Loglarını İzleme
Docker konteynerlerinizin logları, uygulamanızda neler olup bittiğini anlamak için ilk bakmanız gereken yerdir. docker-compose logs -f app komutu, app servisinizin loglarını gerçek zamanlı olarak izlemenizi sağlar. PHP hataları, uyarıları ve özel olarak yazdığınız log mesajları burada görünecektir.
Xdebug ile Adım Adım Hata Ayıklama
Yukarıda belirtildiği gibi Xdebug'ı kurup yapılandırdıktan sonra, IDE'niz üzerinden uygulamanızın kodunu adım adım çalıştırabilir, değişken değerlerini inceleyebilir ve çağrı yığınını (call stack) takip edebilirsiniz. Bu, karmaşık hataları bulmak için en etkili yöntemdir.
1. IDE'nizde bir breakpoint (kesme noktası) belirleyin.
2. IDE'nizin Xdebug dinleyicisini başlatın.
3. Web tarayıcınızdan veya bir API istemcisinden uygulamanıza istek gönderin.
4. Xdebug, breakpoint'e ulaştığında yürütmeyi durduracak ve IDE'nizde hata ayıklama oturumu başlayacaktır.
Ortak Sorunlar ve Çözümleri
* Paket Bulunamıyor: composer.json dosyasındaki path repository'nin url değeri veya paketin name alanı yanlış olabilir. composer validate komutunu kullanarak composer.json dosyanızın geçerliliğini kontrol edin.
* Sembolik Bağlantı Sorunları: Windows'ta symlink: true ile sorun yaşıyorsanız, WSL2 kullandığınızdan emin olun veya symlink: false deneyin.
* Performans Düşüşü: Özellikle macOS ve Windows'ta dosya sistemi performans sorunları yaşıyorsanız, projenizi WSL2 içine taşıyın veya cached/delegated mount seçeneklerini deneyin.
* Xdebug Çalışmıyor: XDEBUG_MODE ve XDEBUG_CONFIG ortam değişkenlerinin doğru ayarlandığından emin olun. client_host değerinin ana bilgisayarınızın IP'sini işaret ettiğinden ve IDE'nizin dinleyici modunda olduğundan emin olun.
* Composer Memory Limit: Büyük projelerde composer update çalıştırırken bellek hatası alabilirsiniz. docker-compose exec app php -d memory_limit=-1 /usr/local/bin/composer update komutunu kullanarak bellek limitini kaldırabilirsiniz.
En İyi Uygulamalar ve İpuçları
Verimli ve sürdürülebilir bir yerel paket geliştirme süreci için bazı en iyi uygulamaları benimsemek önemlidir.
Versiyon Kontrolü (Git) Entegrasyonu
Hem ana projenizi hem de yerel paketinizi ayrı Git depolarında yönetin. Bu, paketinizi daha sonra bağımsız olarak yayınlamanıza veya farklı projelere dahil etmenize olanak tanır. Yerel pakette yaptığınız değişiklikleri düzenli olarak commit edin ve push edin.
Otomatik Testler ve CI/CD
Geliştirdiğiniz her yerel paket için birim (unit) ve entegrasyon (integration) testleri yazın. Bu testleri Docker konteyneri içinde çalıştırmak, ortam bağımsızlığını sağlar. Daha ileri seviyede, paketinizi bir CI/CD (Sürekli Entegrasyon/Sürekli Dağıtım) sürecine dahil ederek her commit'te otomatik testlerin çalışmasını sağlayabilirsiniz.
# Konteyner içinde PHPUnit çalıştırma
docker-compose exec app vendor/bin/phpunit packages/my-local-package/tests
Geliştirme Ortamını Temiz Tutma
Düzenli olarak kullanılmayan Docker imajlarını, konteynerlerini ve volume'lerini temizleyin. Bu, disk alanından tasarruf etmenizi ve olası çakışmaları önlemenizi sağlar.
* docker system prune (kullanılmayan tüm Docker kaynaklarını temizler)
* docker-compose down --volumes --rmi all (belirli bir projenin tüm servislerini durdurur, volume'lerini ve imajlarını kaldırır)
Sonuç
Docker ortamında Composer ile yerel paket geliştirmek, başlangıçta bazı zorluklar barındırsa da, doğru yapılandırma ve iş akışlarıyla oldukça verimli ve keyifli bir deneyime dönüşebilir. docker-compose.yml ve Dockerfile'ınızı titizlikle yapılandırmak, path repositories ve sembolik bağlantıları etkin kullanmak, performans optimizasyonlarına dikkat etmek ve Xdebug ile etkili hata ayıklama yapmak, bu sürecin temel taşlarıdır. Bu makalede sunulan ipuçları ve örnekler sayesinde, kendi yerel Composer paketlerinizi Docker'ın gücüyle sorunsuz bir şekilde geliştirebilir, projelerinizi daha modüler ve sürdürülebilir hale getirebilirsiniz.
SSS (Sık Sorulan Sorular)
1. Yerel paketimi neden path repository ile kullanmalıyım?
path repository, henüz bir paket deposuna (Packagist gibi) yayınlamadığınız veya aktif olarak üzerinde çalıştığınız bir paketi ana projenize kolayca dahil etmenizi sağlar. Bu, her değişiklikte paketi yayınlamak zorunda kalmadan yerel test ve geliştirme yapmanızı mümkün kılar.
2. symlink: true ve symlink: false arasındaki fark nedir?
symlink: true kullanıldığında, Composer yerel paketinize vendor dizini içinde sembolik bir bağlantı oluşturur. Bu, paketin kaynak kodunda yaptığınız değişikliklerin anında ana projede görünmesini sağlar. symlink: false ise paketin bir kopyasını vendor dizinine yerleştirir, bu durumda her değişiklikten sonra composer update çalıştırmanız gerekebilir.
3. Docker'da Composer cache'ini nasıl kalıcı hale getirebilirim?
docker-compose.yml dosyanızda Composer cache dizinini (/root/.composer/cache veya /home//.composer/cache) kalıcı bir Docker volume'a bağlayarak cache'i kalıcı hale getirebilirsiniz. Bu, konteynerler yeniden oluşturulduğunda bağımlılıkların tekrar indirilmesini önler.
4. Xdebug neden Docker konteynerimde çalışmıyor?
Xdebug'ın çalışmamasının birkaç nedeni olabilir:
* Dockerfile'ınızda Xdebug doğru kurulmamış olabilir.
* docker-compose.yml dosyanızda XDEBUG_MODE ve XDEBUG_CONFIG ortam değişkenleri yanlış ayarlanmış olabilir. Özellikle client_host değeri, IDE'nizin çalıştığı ana bilgisayarın IP adresini veya host.docker.internal'ı doğru şekilde göstermelidir.
* IDE'nizin Xdebug dinleyicisi etkinleştirilmemiş olabilir.
5. Yerel paketimde bir değişiklik yaptığımda ana projeyi yeniden derlemem (rebuild) gerekir mi?
Eğer path repository'nizde symlink: true kullandıysanız, genellikle ana projeyi yeniden derlemeniz veya composer update çalıştırmanız gerekmez. Değişiklikler anında yansır. Ancak, paketin composer.json dosyasındaki bağımlılıkları değiştirdiyseniz, ana projenin vendor dizinini güncellemek için docker-compose exec app composer update my-vendor/my-local-package çalıştırmanız gerekebilir.
