docker

Docker Compose 대안

JohnnyDeveloper 2026. 1. 13. 16:13

Docker Compose 대안 완전 가이드

단일 노드 환경에서 컨테이너를 관리하는 4가지 방법

Podman Quadlet Kubernetes Shell Script

Docker Compose는 다중 컨테이너 애플리케이션을 정의하고 실행하는 표준 도구로 자리 잡았습니다. 하지만 모든 상황에 Compose가 최선은 아닙니다. 단일 노드 서버, 엣지 디바이스, 임베디드 시스템, 또는 Podman 기반 환경에서는 더 나은 대안이 있을 수 있습니다.

이 글에서는 Docker Compose를 대체할 수 있는 4가지 주요 방법을 비교하고, 각각의 장단점과 적합한 사용 사례를 살펴봅니다.

왜 Compose 대안을 고려해야 할까?

🔒

보안 요구사항

Rootless 환경이나 SELinux가 강제된 시스템에서 Compose는 제약이 있습니다. systemd 통합이 더 안전할 수 있습니다.

⚙️

시스템 통합

컨테이너를 다른 시스템 서비스와 동일하게 관리하고 싶을 때, systemd 네이티브 방식이 더 자연스럽습니다.

🎯

단순성

2-3개 컨테이너만 실행하는 경우, Compose는 오버엔지니어링일 수 있습니다. 더 간단한 방법이 적합할 수 있습니다.

4가지 대안 비교

🐋

Docker Compose

기준점: 익숙하고 강력하지만, 항상 최선은 아님

  • 직관적인 YAML 문법
  • 풍부한 생태계와 문서
  • 복잡한 네트워크/볼륨 관리
  • Docker 데몬 의존성
  • systemd 통합 제한적
  • Rootless 모드 복잡
📋

Podman Quadlet

systemd 네이티브 방식의 컨테이너 관리 (권장)

  • systemd와 완벽 통합
  • Rootless by default
  • 의존성 관리 내장
  • 자동 업데이트 지원
  • Podman 4.4+ 필요
  • 학습 곡선 (새로운 문법)
  • 상대적으로 신생 기술
☸️

Kubernetes

대규모 오케스트레이션 (단일 노드엔 과함)

  • 업계 표준
  • 강력한 오케스트레이션
  • 수평 확장 용이
  • 단일 노드에 과도한 복잡성
  • 높은 리소스 소비
  • 관리 오버헤드 큼
📜

Shell Script

가장 단순하지만 제한적

  • 매우 단순
  • 추가 도구 불필요
  • 완전한 제어
  • 오류 처리 어려움
  • 의존성 관리 수동
  • 상태 추적 없음
  • 재현성 낮음

1. Podman Quadlet: 현대적인 systemd 통합

Quadlet은 Podman 4.4부터 공식 포함된 systemd 제너레이터입니다. Kubernetes YAML과 유사한 선언적 문법으로 컨테이너를 정의하고, systemd가 자동으로 서비스 파일을 생성합니다.

🎯
Quadlet의 핵심 철학

Compose나 Kubernetes처럼 "무엇을 실행할지" 선언하되, systemd의 프로세스 관리와 완벽하게 통합되어 Linux 시스템의 일급 시민으로 동작합니다.

Quadlet 기본 예제

간단한 nginx 컨테이너를 systemd 서비스로 실행해보겠습니다.

# ~/.config/containers/systemd/nginx.container

[Unit]
Description=Nginx Web Server
After=network-online.target

[Container]
Image=docker.io/library/nginx:alpine
PublishPort=8080:80
Volume=nginx-data.volume:/usr/share/nginx/html:Z

[Service]
Restart=always
TimeoutStartSec=900

[Install]
WantedBy=multi-user.target default.target
# ~/.config/containers/systemd/nginx-data.volume

[Volume]
VolumeName=nginx-data
# systemd daemon reload 후 서비스 시작
systemctl --user daemon-reload
systemctl --user start nginx
systemctl --user enable nginx

# 상태 확인
systemctl --user status nginx
journalctl --user -u nginx -f

복잡한 예제: WordPress + MySQL Pod

여러 컨테이너를 Pod로 묶어 네트워크를 공유할 수 있습니다.

# ~/.config/containers/systemd/wordpress.pod

[Unit]
Description=WordPress Application Pod
After=network-online.target

[Pod]
PodName=wordpress
PublishPort=8080:80

[Install]
WantedBy=multi-user.target default.target
# ~/.config/containers/systemd/wordpress-db.container

[Unit]
Description=WordPress Database
Requires=wordpress.service
After=wordpress.service

[Container]
Image=docker.io/library/mysql:8.0
Pod=wordpress.pod
Volume=wordpress-db.volume:/var/lib/mysql:Z
Environment=MYSQL_ROOT_PASSWORD=secret
Environment=MYSQL_DATABASE=wordpress
Environment=MYSQL_USER=wpuser
Environment=MYSQL_PASSWORD=wppass

[Service]
Restart=always

[Install]
WantedBy=multi-user.target default.target
# ~/.config/containers/systemd/wordpress-app.container

[Unit]
Description=WordPress Application
Requires=wordpress-db.service
After=wordpress-db.service

[Container]
Image=docker.io/library/wordpress:latest
Pod=wordpress.pod
Volume=wordpress-app.volume:/var/www/html:Z
Environment=WORDPRESS_DB_HOST=localhost
Environment=WORDPRESS_DB_USER=wpuser
Environment=WORDPRESS_DB_PASSWORD=wppass
Environment=WORDPRESS_DB_NAME=wordpress

[Service]
Restart=always

[Install]
WantedBy=multi-user.target default.target
💡
Pod 네트워크 공유

Pod 내부의 컨테이너들은 localhost로 서로 통신할 수 있습니다. MySQL을 localhost:3306로 접근하는 것을 확인하세요. Compose의 service discovery와 동일한 효과입니다.

Kubernetes YAML 지원

기존 Kubernetes 매니페스트를 재사용할 수 있습니다.

# ~/.config/containers/systemd/myapp.kube

[Unit]
Description=My K8s Application
After=network-online.target

[Kube]
Yaml=myapp-deployment.yaml
ConfigMap=myapp-config.yaml

[Service]
Restart=always

[Install]
WantedBy=multi-user.target default.target

자동 업데이트

Quadlet의 강력한 기능 중 하나는 자동 이미지 업데이트입니다.

# .container 파일에 추가
[Container]
AutoUpdate=registry

# 자동 업데이트 실행 (systemd timer로 주기적 실행 가능)
podman auto-update

Compose → Quadlet 마이그레이션

podlet 도구를 사용하면 Compose 파일을 Quadlet으로 쉽게 변환할 수 있습니다.

# podlet 설치
cargo install podlet

# Compose 파일을 Quadlet으로 변환
podlet compose docker-compose.yaml > myapp.container

# Podman 명령어를 Quadlet으로 변환
podlet podman run -d -p 8080:80 nginx > nginx.container

2. Kubernetes: 대규모 오케스트레이션

Kubernetes는 강력하지만, 단일 노드 환경에서는 과도한 복잡성을 초래합니다.

⚠️
단일 노드에서 Kubernetes는 오버킬

3-5개 컨테이너를 실행하는 홈 서버나 엣지 디바이스에서 Kubernetes를 운영하는 것은 리소스 낭비이며, 관리 복잡도만 증가시킵니다. Control Plane만으로도 최소 1-2GB RAM이 필요합니다.

Kubernetes가 적합한 경우

  • 다중 노드 클러스터 (최소 3개 이상)
  • 수평 확장(auto-scaling)이 필수인 워크로드
  • 복잡한 서비스 메시와 트래픽 관리
  • 이미 조직 전체가 Kubernetes 표준을 사용
  • Helm 차트 같은 패키징 도구 활용

단일 노드 Kubernetes 대안

만약 Kubernetes를 배우거나 개발 환경이 필요하다면:

# k3s: 경량 Kubernetes (단일 바이너리, 512MB RAM)
curl -sfL https://get.k3s.io | sh -

# MicroK8s: Canonical의 경량 배포판
snap install microk8s --classic

# Kind: Docker-in-Docker 개발 클러스터
kind create cluster
💡
Quadlet + Kubernetes YAML

Quadlet의 .kube 파일을 사용하면 Kubernetes YAML을 그대로 사용하면서도 Kubernetes 클러스터 없이 단일 노드에서 실행할 수 있습니다. 두 세계의 장점을 모두 가져가세요!

3. Shell Script: 단순함의 극치

가장 단순한 방법은 podman run 명령어를 스크립트로 묶는 것입니다.

기본 예제

#!/bin/bash
# run-containers.sh

set -e

# 네트워크 생성
podman network create myapp-net || true

# MySQL 시작
podman run -d \
  --name myapp-db \
  --network myapp-net \
  -v myapp-db-data:/var/lib/mysql:Z \
  -e MYSQL_ROOT_PASSWORD=secret \
  -e MYSQL_DATABASE=myapp \
  mysql:8.0

# 앱 시작 (DB 준비 대기)
sleep 10

podman run -d \
  --name myapp-web \
  --network myapp-net \
  -p 8080:80 \
  -e DB_HOST=myapp-db \
  -e DB_NAME=myapp \
  myapp:latest

echo "Containers started successfully!"

Shell Script의 문제점

오류 처리 어려움

컨테이너가 실패하면? 재시작은? 의존성 순서는? 모두 수동으로 구현해야 합니다.

상태 관리 없음

스크립트를 두 번 실행하면? 이미 실행 중인지 확인하는 로직이 필요합니다.

부팅 시 자동 시작

결국 systemd 서비스 파일을 만들어야 합니다. 그럼 처음부터 Quadlet을 쓰는 게 낫습니다.

그래도 Shell Script를 쓴다면

최소한 다음 사항을 고려하세요:

#!/bin/bash
# 개선된 run-containers.sh

set -euo pipefail

# 색상 정의
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'

# 로깅 함수
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1" >&2
}

# 컨테이너 존재 확인
container_exists() {
    podman ps -a --format '{{.Names}}' | grep -q "^$1$"
}

# 컨테이너 실행 중 확인
container_running() {
    podman ps --format '{{.Names}}' | grep -q "^$1$"
}

# MySQL 시작
if container_exists "myapp-db"; then
    if container_running "myapp-db"; then
        log_info "Database already running"
    else
        log_info "Starting existing database container"
        podman start myapp-db
    fi
else
    log_info "Creating database container"
    podman run -d \
      --name myapp-db \
      --network myapp-net \
      -v myapp-db-data:/var/lib/mysql:Z \
      -e MYSQL_ROOT_PASSWORD=secret \
      mysql:8.0 || {
        log_error "Failed to start database"
        exit 1
    }
fi

# Health check 대기
log_info "Waiting for database to be ready..."
for i in {1..30}; do
    if podman exec myapp-db mysqladmin ping -h localhost -proot &> /dev/null; then
        log_info "Database is ready!"
        break
    fi
    sleep 1
done

log_info "All containers started successfully!"
⚠️
결론: Shell Script는 최후의 수단

2-3개 컨테이너를 일회성으로 실행하는 경우가 아니라면, Quadlet이나 Compose를 사용하세요. 장기적으로 유지보수가 훨씬 쉽습니다.

비교표: 어떤 것을 선택할까?

특성 Compose Quadlet Kubernetes Shell Script
학습 곡선 낮음 중간 높음 매우 낮음
systemd 통합 제한적 완벽 없음 수동
의존성 관리 자동 자동 (systemd) 자동 수동
자동 재시작 있음 있음 (systemd) 있음 수동
Health Check 있음 있음 고급 수동
로그 관리 docker logs journalctl kubectl logs stdout/stderr
네트워크 자동 생성 선언적 고급 (CNI) 수동
볼륨 관리 자동 선언적 PV/PVC 수동
다중 노드 불가 불가 가능 불가
Rootless 복잡 기본 불가 가능
리소스 사용 낮음 매우 낮음 높음 매우 낮음
적합한 규모 1-50 컨테이너 1-20 컨테이너 50+ 컨테이너 1-3 컨테이너

의사결정 가이드

어떤 방법을 선택해야 할까?

Podman Quadlet을 선택하세요

Linux 서버, 엣지 디바이스, Rootless 환경, systemd 기반 시스템, 1-20개 컨테이너, 장기 운영 서비스

Docker Compose를 선택하세요

개발 환경, Docker 기반 워크플로우, 팀 전체가 Compose에 익숙, Windows/macOS 개발자, 빠른 프로토타이핑

?

Kubernetes를 고려하세요

다중 노드 클러스터, 수평 확장 필수, 조직 표준이 K8s, 50개 이상 컨테이너, 복잡한 네트워크 정책

Shell Script는 피하세요

장기 운영 서비스, 4개 이상 컨테이너, 의존성이 복잡한 경우 - 대신 Quadlet이나 Compose 사용 권장

실전 시나리오

시나리오 1: 홈 서버 (Self-Hosted Services)

요구사항

  • Nextcloud, Jellyfin, Pi-hole, Home Assistant 실행
  • 부팅 시 자동 시작
  • Rootless 실행 (보안)
  • systemd로 중앙 관리

추천: Podman Quadlet

각 서비스를 .container 파일로 정의하고 systemd가 관리하도록 합니다. systemctl --user enable --now nextcloud 명령 하나로 서비스 시작 및 활성화.

시나리오 2: 개발 환경

요구사항

  • Node.js 앱 + PostgreSQL + Redis
  • 빠른 반복 개발
  • 팀 전체가 동일한 환경
  • macOS와 Linux 혼용

추천: Docker Compose

docker-compose.yml 하나로 전체 스택을 정의하고 docker compose up으로 즉시 시작. 크로스 플랫폼 지원.

시나리오 3: 엣지 디바이스 (IoT Gateway)

요구사항

  • MQTT Broker + Node-RED
  • 최소 리소스 (512MB RAM)
  • 무인 운영 (자동 재시작 필수)
  • SELinux 강제 모드

추천: Podman Quadlet

Rootless Quadlet으로 최소 리소스로 안정적 운영. systemd의 강력한 재시작 정책 활용.

시나리오 4: 마이크로서비스 (Production)

요구사항

  • 50+ 마이크로서비스
  • Auto-scaling 필요
  • 다중 노드 클러스터
  • 서비스 메시, Ingress 필요

추천: Kubernetes (K3s/K8s)

이 규모에서는 Kubernetes가 정답입니다. Compose나 Quadlet로는 관리 불가능.

Quadlet 고급 기능

커스텀 네트워크

# ~/.config/containers/systemd/myapp-net.network

[Network]
NetworkName=myapp-net
Subnet=10.89.0.0/24
Gateway=10.89.0.1
Label=app=myapp

Secret 관리

# Secret 생성
echo -n "my-secret-password" | podman secret create db-password -

# .container 파일에서 사용
[Container]
Secret=db-password,type=env,target=DB_PASSWORD

Health Check

[Container]
HealthCmd=curl -f http://localhost/health || exit 1
HealthInterval=30s
HealthRetries=3
HealthStartPeriod=60s
HealthTimeout=10s

마치며

Docker Compose 대안을 선택하는 것은 단순히 도구를 바꾸는 것이 아니라, 시스템 아키텍처 철학을 선택하는 것입니다.

Quadlet을 선택하세요

  • Linux 서버 운영
  • systemd 통합 선호
  • Rootless 보안 필수
  • 장기 안정성 중요
  • 1-20개 컨테이너

Compose를 유지하세요

  • 개발 환경
  • 크로스 플랫폼
  • 팀이 Compose에 익숙
  • 빠른 프로토타이핑
  • Docker 에코시스템
🎯
핵심 요약

단일 노드 Linux 서버라면 Quadlet이 최선입니다. systemd의 강력한 프로세스 관리와 Podman의 보안성을 결합하여, Compose보다 더 안전하고 Kubernetes보다 훨씬 단순합니다. Podman 4.4 이상이라면 지금 바로 시작하세요.

다음 단계

  1. 기존 Compose 파일을 podlet으로 Quadlet 변환
  2. ~/.config/containers/systemd/에 파일 배치
  3. systemctl --user daemon-reload 실행
  4. systemctl --user start <service>로 테스트
  5. journalctl --user -u <service> -f로 로그 확인