1. 라라벨 배포에 Docker Compose가 필수적인 이유
전통적인 LAMP 또는 LEMP 스택을 이용한 수동 배포 방식은 '환경의 파편화'라는 고질적인 문제를 안고 있습니다. 특정 서버에서는 PHP 확장이 누락되거나, 로컬과 운영 서버의 라이브러리 버전이 미세하게 달라 발생하는 오류는 프로젝트의 안정성을 해칩니다. Ubuntu 20.04 LTS 환경에서 Docker Compose를 사용하는 것은 단순한 유행이 아니라, 인프라를 코드로 관리(IaC)하여 환경의 불확실성을 제거하는 엔지니어링의 필수 과정입니다.
Docker Compose를 사용하면 Nginx, PHP-FPM, MySQL, Redis와 같은 다중 컨테이너 서비스를 선언적인 YAML 파일 하나로 제어할 수 있습니다. 이는 개발자 개개인의 로컬 환경부터 스테이징, 운영 환경에 이르기까지 동일한 실행 컨텍스트를 보장하며, 서비스 확장 및 마이그레이션 시 발생할 수 있는 리스크를 최소화합니다.
2. 핵심 엔진 설치: Docker 및 Docker Compose V2
Ubuntu 20.04의 기본 저장소(apt)에서 제공하는 docker-compose 패키지는 구버전인 V1(Python 기반)인 경우가 많습니다. 최신 Laravel 프레임워크와의 호환성과 성능을 위해 Go 언어로 작성된 Docker Compose V2를 직접 설치하는 것이 권장됩니다.
Docker Engine 설치 및 저장소 구성
# 시스템 패키지 업데이트 및 필수 의존성 설치
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release -y
# Docker 공식 GPG 키 등록
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# Docker 저장소 설정
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Docker 엔진 설치
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin -y
Docker Compose V2 플러그인 설치
Compose V2는 Docker CLI의 플러그인 형태로 작동합니다. docker-compose가 아닌 docker compose 명령어를 사용하게 됩니다.
# CLI 플러그인 디렉토리 생성
mkdir -p ~/.docker/cli-plugins/
# 최신 버전의 Compose 바이너리 다운로드 (예: v2.26.1)
LATEST_COMPOSE_VER="v2.26.1"
curl -SL "https://github.com/docker/compose/releases/download/${LATEST_COMPOSE_VER}/docker-compose-linux-x86_64" -o ~/.docker/cli-plugins/docker-compose
# 실행 권한 부여
chmod +x ~/.docker/cli-plugins/docker-compose
# 설치 확인
docker compose version
3. 사용자 권한 최적화 및 보안 설정
매번 sudo 명령어를 사용하는 것은 번거로울 뿐 아니라 보안상 권장되지 않습니다. 현재 사용자를 docker 그룹에 추가하여 권한 문제를 해결하되, 변경 사항이 즉시 적용되지 않는 점에 주의해야 합니다.
# 현재 사용자를 docker 그룹에 추가
sudo usermod -aG docker ${USER}
# 그룹 변경 사항을 현재 세션에 즉시 적용 (또는 재로그인 필요)
newgrp docker
# 권한 확인을 위한 테스트 컨테이너 실행
docker run --rm hello-world
주의:
usermod명령을 실행한 후에도 권한 오류가 발생한다면, 시스템 세션을 완전히 종료하고 다시 로그인하거나 서버를 재부팅하여 그룹 식별자가 환경에 반영되도록 해야 합니다.
4. Laravel 프로젝트 구조의 표준화
Docker 환경에서 Laravel을 구동할 때는 파일 권한과 디렉토리 구조를 컨테이너 중심적으로 재설계해야 합니다. 특히 storage 및 bootstrap/cache 디렉토리는 PHP-FPM 컨테이너 내의 프로세스가 쓰기 권한을 가져야 합니다.
전형적인 Docker 기반 Laravel 프로젝트의 핵심 구성 요소는 다음과 같습니다:
- docker-compose.yml: 서비스 정의 (App, Web, DB).
- docker/nginx/default.conf: PHP-FPM 연결을 위한 웹 서버 설정.
- Dockerfile: PHP 확장이 포함된 애플리케이션 이미지 빌드 명세.
애플리케이션 소스를 컨테이너 내부로 마운트할 때, .env 파일의 DB_HOST나 REDIS_HOST는 localhost가 아닌 docker-compose.yml에 정의된 서비스 이름을 참조하도록 설정해야 합니다. 예를 들어 데이터베이스 서비스 이름이 db라면, 환경 설정은 DB_HOST=db가 됩니다.
5. 컨테이너 오케스트레이션 기초 (docker-compose.yml)
아래는 Laravel 서비스를 위한 docker-compose.yml 파일의 논리적 구조 예시입니다. 개별 프로젝트 환경에 맞춰 볼륨 경로와 포트 설정을 조정할 수 있습니다.
services:
# PHP-FPM 애플리케이션 서비스
laravel-app:
build:
context: .
dockerfile: Dockerfile
container_name: lara_backend
volumes:
- .:/var/www/html
networks:
- backend_network
# Nginx 웹 서버
web-server:
image: nginx:stable-alpine
container_name: lara_web
ports:
- "8080:80"
volumes:
- .:/var/www/html
- ./docker/nginx/conf.d:/etc/nginx/conf.d
depends_on:
- laravel-app
networks:
- backend_network
networks:
backend_network:
driver: bridge
이러한 구성은 서비스 간의 격리를 보장하면서도 브리지 네트워크를 통해 원활한 통신을 가능하게 합니다. 또한, 호스트의 8080 포트를 통해 웹 서비스에 접근할 수 있도록 포워딩을 설정하여 기존 시스템의 포트 충돌을 방지합니다.