로컬 스택을 위한 Docker Compose
로컬에서 PHP, 데이터베이스와 캐시를 함께 실행합니다.
로컬 스택을 위한 Docker Compose은(는) CoddyKit의 무료 PHP Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 PHP Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. PHP Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
Compose로 로컬 스택 구성
실제 PHP 앱은 PHP만으로 구성되지 않습니다. 데이터베이스, 캐시, 경우에 따라 큐와 메일 수신기가 필요합니다. Docker Compose는 이러한 요소를 하나의 파일에서 서비스로 선언하고, 공유 네트워크에 연결하여 서로 이름으로 접근할 수 있게 합니다.
이 레슨에서는 볼륨, 상태 확인, 의존성 순서 지정을 포함한 완전한 로컬 스택인 PHP-FPM + nginx + MySQL + Redis를 구성합니다.
서비스 뼈대
Compose 파일은 services: 아래에 서비스를 나열합니다. 각 서비스는 Dockerfile에서 build하거나 image를 가져올 수 있습니다. Compose는 모든 서비스가 키로 접근할 수 있는 기본 네트워크를 생성합니다. PHP 앱은 호스트 db를 통해 MySQL에 연결하며, localhost를 사용하지 않습니다.
services:
app:
build:
context: .
target: dev # multi-stage dev target
volumes:
- ./:/app # live code mount
depends_on:
db:
condition: service_healthy
db:
image: mysql:8.4
redis:
image: redis:7-alpineFPM 앞에 nginx 배치
FPM은 HTTP가 아니라 포트 9000에서 FastCGI로 통신합니다. nginx는 HTTP를 종료하고 .php 요청을 app:9000으로 전달합니다. nginx 설정은 Compose 이름으로 PHP 서비스를 참조합니다.
# docker/nginx/default.conf
server {
listen 80;
root /app/public;
index index.php;
location / {
try_files $uri /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass app:9000; # service name from compose
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}웹 서비스 연결
nginx 서비스는 동일한 소스 코드(SCRIPT_FILENAME을 확인하기 위해)와 설정을 마운트하고, 포트 80을 공개하며, 앱 서비스에 의존합니다. 양쪽이 /app을 공유하므로 FastCGI의 양쪽에서 경로가 일치합니다.
services:
web:
image: nginx:1.27-alpine
ports:
- "8080:80"
volumes:
- ./:/app:ro
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- app영속 볼륨
컨테이너의 파일 시스템은 일시적입니다. 이름이 지정된 볼륨은 docker compose down을 실행해도 데이터베이스 파일을 유지합니다. 바인드 마운트(./:/app)는 개발 중 호스트 코드를 실시간으로 동기화합니다. 상태가 있는 데이터에는 이름이 지정된 볼륨을, 소스 코드에는 바인드 마운트를 사용하십시오.
services:
db:
image: mysql:8.4
environment:
MYSQL_DATABASE: app
MYSQL_USER: app
MYSQL_PASSWORD: secret
MYSQL_ROOT_PASSWORD: rootsecret
volumes:
- dbdata:/var/lib/mysql
volumes:
dbdata: # survives `down`, removed only by `down -v`상태 확인과 의존성 설정
depends_on만 사용하면 컨테이너가 시작될 때까지만 기다리며, MySQL이 연결을 수락할 때까지 기다리지는 않습니다. healthcheck를 추가하고 condition: service_healthy를 사용하여 데이터베이스가 실제로 준비될 때까지 앱이 기다리도록 하십시오.
services:
db:
image: mysql:8.4
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-prootsecret"]
interval: 5s
timeout: 3s
retries: 10
app:
build: .
depends_on:
db:
condition: service_healthy # waits for healthcheck pass환경 변수와 .env
Compose는 변수 치환을 위해 같은 디렉터리에 있는 .env를 자동으로 불러오며, environment 또는 env_file을 통해 앱 설정을 전달합니다. 커밋하는 Compose 파일에 비밀 정보를 넣지 말고 변수로 참조하십시오.
services:
app:
build: .
env_file:
- .env
environment:
DATABASE_URL: "mysql://app:secret@db:3306/app"
REDIS_URL: "redis://redis:6379"
# .env (gitignored) provides ${...} substitutions
# MYSQL_PASSWORD=secretPHP에서 연결하기
네트워크 내부에서는 호스트 이름이 서비스 이름입니다. PHP 코드는 db와 redis에 직접 연결합니다. 이 예제는 설정 계층에서 사용하는 방식으로 DSN을 분석하여, Compose 서비스 이름이 연결 문자열에 어떻게 전달되는지 보여 줍니다.
<?php
$dsn = 'mysql://app:secret@db:3306/app';
$p = parse_url($dsn);
printf("driver: %s\n", $p['scheme']);
printf("host: %s\n", $p['host']); // 'db' resolves via compose DNS
printf("port: %d\n", $p['port']);
printf("db: %s\n", ltrim($p['path'], '/'));
$pdoDsn = sprintf('mysql:host=%s;port=%d;dbname=%s', $p['host'], $p['port'], ltrim($p['path'], '/'));
echo $pdoDsn . PHP_EOL;
?>로컬 개발용 Xdebug
Xdebug 설정은 로컬에서만(dev 빌드 대상을 통해) 마운트하십시오. client_host를 host.docker.internal로 지정하면 디버거가 호스트의 IDE에 연결할 수 있습니다. Xdebug를 운영 환경에 절대 배포하지 마십시오. 성능을 심각하게 저하시킵니다.
; docker/php/xdebug.ini (mounted only in dev)
zend_extension=xdebug
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003일회성 명령 실행
docker compose run은 마이그레이션, 테스트 또는 Composer를 위한 임시 컨테이너를 실행하고, exec은 이미 실행 중인 서비스 내부에서 실행합니다. 작업에는 run --rm을 사용하여 일회성 컨테이너가 정리되도록 하십시오.
# Run migrations against the running db
docker compose exec app php bin/console doctrine:migrations:migrate
# One-off: install deps without a long-lived container
docker compose run --rm app composer install
# Tail logs of just the web service
docker compose logs -f web재정의 파일
Compose는 docker-compose.yml과 docker-compose.override.yml을 자동으로 병합합니다. 기본 파일에는 운영 환경과 같은 기본 설정을 유지하고, 개발 전용 볼륨, 포트, Xdebug는 재정의 파일에 넣으십시오. 그러면 CI는 기본 파일을 사용하고 개발자는 추가 설정을 별도 작업 없이 사용할 수 있습니다.
# docker-compose.override.yml (auto-merged, dev only)
services:
app:
volumes:
- ./docker/php/xdebug.ini:/usr/local/etc/php/conf.d/xdebug.ini:ro
environment:
APP_ENV: dev
# CI runs: docker compose -f docker-compose.yml up (no override)빠른 확인
마이그레이션을 실행하기 전에 단순한 depends_on: [db]만으로는 충분하지 않은 이유는 무엇입니까?
요약
Compose로 로컬 스택을 구성했습니다. nginx 뒤에 PHP-FPM을 배치하고(app:9000으로 FastCGI 연결), 서비스 이름으로 MySQL과 Redis에 접근하며, 영속성을 위해 이름이 지정된 볼륨을 사용하고, 상태 확인으로 depends_on의 실행을 제어했습니다. 또한 환경 변수 기반 설정, 개발 전용 재정의 파일의 Xdebug, run/exec을 통한 일회성 명령을 구성했습니다.
기억할 점: 서비스 이름은 DNS 호스트 이름이고, 재정의 파일은 개발용 추가 설정을 CI에서 분리하며, 상태 확인은 단순한 시작 순서 지정 방식보다 안정적입니다.
자주 묻는 질문
“로컬 스택을 위한 Docker Compose” 강의는 무료인가요?
네 — “로컬 스택을 위한 Docker Compose” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 PHP Academy 강의 전체를 잠금 해제할 수 있습니다. PHP Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“로컬 스택을 위한 Docker Compose”에서 뭘 배우나요?
로컬에서 PHP, 데이터베이스와 캐시를 함께 실행합니다. 브라우저에서 직접 실행하는 실습 코드로 PHP Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
PHP Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 PHP Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“로컬 스택을 위한 Docker Compose” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 PHP Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 PHP Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- PHP 애플리케이션 컨테이너화
- 다단계 빌드와 최적화
- 로컬 스택을 위한 Docker Compose
- GitHub Actions로 CI/CD 구축