Docker 대신 systemd.service? 리눅스에서 웹 애플리케이션 배포 전략 다시 보기

최근 몇 년간 “배포 = Docker + 컨테이너 오케스트레이션(Kubernetes, ECS 등)”이라는 공식이 거의 상식처럼 되어 버렸습니다. 그래서인지 리눅스 서버에 웹 애플리케이션을 그냥 프로세스 + systemd 서비스로 올리는 방식은 구식처럼 느껴지기도 합니다.

하지만 현실적으로는:

  • 단일 웹 애플리케이션
  • 소규모 팀 / 단순 인프라
  • 온프레미스나 규제가 강한 환경

에서는 여전히 systemd 서비스로 배포하는 것이 더 단순하고, 안정적이고, 운영 친화적인 선택일 때가 많습니다.

이 글에서는 리눅스의 systemd.service로 웹 애플리케이션을 배포할 때 Docker 대비 어떤 장점이 있는지, 그리고 어떤 상황에서 systemd 기반 배포가 더 도움이 되는지 정리해 보겠습니다.


1. systemd와 Docker를 간단히 짚고 가기



먼저 개념을 아주 짧게만 정리해보면:

  • Docker

  • 애플리케이션을 이미지로 패키징하고

  • 컨테이너로 실행하는 기술
  • “환경 통째로 캡슐화 → 어디서나 동일하게 실행”이 강점

  • systemd

  • 현대 리눅스 배포판의 기본 init 시스템

  • 부팅 시 서비스(데몬)를 올리고, 죽으면 다시 살리고, 로그를 관리하는 역할
  • *.service 유닛 파일로 프로세스를 정의하고 관리

Docker는 애플리케이션 환경을 캡슐화하는 도구이고, systemd는 리눅스에서 프로세스를 관리하는 도구입니다.

둘은 경쟁 관계라기보다는, 오히려 “Docker 컨테이너 안에서 systemd를 쓰거나”, “Docker 데몬 자체를 systemd가 관리한다”처럼 함께 쓰는 경우도 많습니다.

하지만 여기서는 “웹 애플리케이션을 배포할 때, 아예 Docker를 쓰지 않고 systemd만으로 운영하는 케이스”에 집중해 보겠습니다.


2. Docker 대신 systemd.service 배포의 장점

2-1. 단순함: 레이어가 한 단계 줄어든다

Docker를 사용하면 운영 스택에 이런 요소들이 추가됩니다.

  • Docker 데몬
  • 이미지 빌드 파이프라인
  • 이미지 저장소(Registry)
  • 컨테이너 런타임 권한/권한 관리

반면, systemd 기반 배포는:

  • OS에 필요한 런타임(Python/Node/Java 등)을 설치하고
  • 애플리케이션 코드를 배포하고
  • systemd 서비스로 등록해서 실행

이라는 상대적으로 단순한 구조입니다.

소규모 프로젝트나 내부 서비스에서는:

  • “이미지 빌드 → 푸시 → 풀 → 재배포” 과정이 오히려 부담이 될 수 있고
  • 서버에 SSH 들어가서 git pull + systemctl restart 정도가 더 빠르고 직관적일 때도 많습니다.

2-2. 리눅스와의 자연스러운 통합

systemd는 리눅스의 “민원창구” 같은 존재라서, OS 레벨 기능과 아주 잘 붙습니다.

  • 로그

  • journalctl -u myapp.service로 서비스 로그를 바로 확인

  • 부팅 자동 실행

  • systemctl enable myapp.service 한 번이면 부팅 시 자동 시작

  • 리소스 제한(cgroup)

  • MemoryMax, CPUQuota 등의 옵션으로 간단한 리소스 제어

  • 의존성 관리

  • After=network.target / After=postgresql.service 등으로 서비스 간 순서 제어

Docker로 서비스를 올리면:

  • 컨테이너 안과 밖의 로그/리소스/네트워크를 구분해서 봐야 하고
  • 문제가 발생했을 때 “이게 컨테이너 문제인지, 호스트 문제인지”를 또 나눠서 봐야 합니다.

단순히 한두 개의 웹 서비스만 운영한다면, 운영/디버깅 관점에서는 systemd 직결 구조가 더 직관적인 경우가 많습니다.

2-3. 리소스 오버헤드 적음

Docker 자체의 오버헤드는 크지 않지만, 실제로는 다음이 함께 따라오는 경우가 많습니다.

  • 여러 이미지/레이어가 쌓이면서 디스크 사용량 증가
  • 불필요하게 올라가 있는 컨테이너들
  • 컨테이너별 로그/볼륨 관리

systemd 기반 배포는:

  • OS + 런타임 + 애플리케이션 코드 정도만 있으면 되기 때문에
  • 특히 디스크/메모리 리소스가 타이트한 환경에서는 더 단순합니다.

소규모 VM 여러 대를 운영하거나, 임베디드/저사양 서버에 올려야 하는 경우라면 systemd가 훨씬 가볍게 느껴집니다.

2-4. 네트워크 구조가 직관적이다

Docker 컨테이너를 사용하면 기본적으로:

  • 컨테이너 내부 IP와 포트
  • 호스트와의 포트 매핑
  • 브리지 네트워크 / 오버레이 네트워크

등을 이해해야 합니다.

반면 systemd 서비스는:

  • 그냥 호스트의 IP/포트에 직접 바인딩
  • 방화벽 규칙도 호스트 기준으로 설정

이기 때문에, 기본적인 네트워크 디버깅이 훨씬 단순합니다.

  • “이 포트가 열려 있는가?”
  • “방화벽에서 막힌 건 아닌가?”
  • “같은 서버의 다른 서비스와 충돌하지는 않는가?”

등을 생각할 때, 하나의 레이어(컨테이너 네트워크)가 줄어드는 효과가 있습니다.

2-5. 특정 환경에서는 Docker를 쓸 수 없다

생각보다 자주 있는 케이스입니다.

  • 금융, 공공, 의료 등 규제가 강한 온프레미스 환경
  • 운영 정책상 “컨테이너 런타임 금지”
  • 인터넷이 제한된 환경이라 외부 레지스트리 사용이 어려운 경우

이런 경우에는 애초에 선택지가 “OS + systemd” 뿐인 경우도 많습니다. 이때 systemd를 잘 이해하고 있으면, 굳이 Docker 없이도 충분히:

  • 자동 재시작
  • 로그 관리
  • 리소스 제한
  • 헬스 체크(간접적으로)

까지 구현할 수 있습니다.


3. systemd.service 예시: 웹 애플리케이션 배포



간단한 예시로, gunicorn으로 Django/Flask 앱을 서비스한다고 가정해 보겠습니다.

3-1. 유닛 파일 예시

/etc/systemd/system/myapp.service:

[Unit]
Description=My Web Application (Gunicorn)
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/srv/myapp
EnvironmentFile=/etc/myapp.env
ExecStart=/usr/bin/gunicorn \
    --workers 4 \
    --bind 0.0.0.0:8000 \
    config.wsgi:application

# 프로세스가 죽으면 자동 재시작
Restart=on-failure
RestartSec=5

# 리소스 제한 예시 (선택)
# MemoryMax=512M
# CPUQuota=50%

[Install]
WantedBy=multi-user.target

그리고 환경 변수는 /etc/myapp.env 같은 파일로 분리:

DJANGO_SETTINGS_MODULE=config.settings.prod
SECRET_KEY=super-secret-key
DATABASE_URL=postgres://...

이후 커맨드는 매우 단순합니다.

# 서비스 등록 & 부팅시 자동 실행
sudo systemctl enable myapp.service

# 시작 / 중지 / 재시작
sudo systemctl start myapp.service
sudo systemctl restart myapp.service
sudo systemctl stop myapp.service

# 상태 / 로그 확인
sudo systemctl status myapp.service
sudo journalctl -u myapp.service -f

이미 리눅스 서버에 익숙한 운영팀이라면, 추가 러닝 커브 없이 바로 운영할 수 있는 구조입니다.


4. 언제 systemd 배포가 Docker보다 더 나을까?

정리해서, 다음과 같은 상황이라면 Docker 대신 systemd 배포를 적극 고려해 볼 만합니다.

4-1. 단일/소규모 서비스, 복잡한 오케스트레이션이 필요 없을 때

  • 웹 애플리케이션 1~2개
  • DB는 RDS 같은 매니지드 서비스 사용
  • 배포 대상 서버 수가 많지 않음 (예: 1~5대 정도)

이런 상황에서는:

  • Docker + 오케스트레이션 도입 비용이 실제 이득보다 더 클 수 있고
  • systemd + 간단한 배포 스크립트(Ansible, Fabric 등)로 충분한 경우가 많습니다.

4-2. 운영팀/인프라팀이 “리눅스 서버 + 서비스”에 익숙한 조직

  • 기존 시스템이 대부분 systemd 기반으로 돌아가고
  • 운영팀이 이미 systemctl, journalctl, rsyslog, logrotate 등에 익숙할 때

굳이 Docker라는 새로운 레이어를 추가해:

  • 권한 모델
  • 네트워크 모델
  • 이미지 관리

를 새로 도입하는 것보다, 기존 운영 스택 위에 웹 애플리케이션을 자연스럽게 올리는 것이 더 효율적일 수 있습니다.

4-3. 규제가 강하거나 Docker 사용이 제한된 환경

앞서 언급한 것처럼:

  • 금융/공공/국방/의료
  • 폐쇄망/내부망
  • 컨테이너 보안 평가/인증 절차가 번거로운 곳

에서는 Docker 도입 자체가 프로젝트 리스크가 될 수 있습니다. 이 경우에는:

  • OS 패키지 / 런타임 설치
  • 코드 배포
  • systemd 서비스 등록

이라는 검증된 패턴이 오히려 가장 현실적인 선택입니다.

4-4. 디버깅/성능 분석 시 호스트와의 간격을 줄이고 싶을 때

  • 직접 strace, perf, /proc를 들여다보며 튜닝해야 하는 상황
  • 네트워크/파일 시스템/리소스 이슈를 한 번에 보고 싶은 상황

에서는 컨테이너를 한 번 더 까고 들어가는 것보다, 호스트 프로세스로 떠 있는 웹 애플리케이션을 바로 분석하는 것이 더 편합니다.


5. 물론, Docker가 더 맞는 상황도 분명 있다

여기까지 systemd 배포의 장점을 이야기했지만, Docker의 장점도 분명합니다.

  • 이미지로 빌드 → 어디서나 동일한 환경
  • 로컬/스테이징/프로덕션 환경 차이 줄이기
  • CI/CD 파이프라인과의 자연스러운 통합
  • 멀티 서비스(웹 + 워커 + 크론 + DB 등) 구성

여러 서버/환경에 똑같은 애플리케이션 스택을 반복해서 배포해야 하거나, 팀 내에서 환경 차이가 너무 큰 경우라면 Docker가 더 나은 선택일 가능성이 큽니다.

결국 중요한 것은:

“우리 서비스 규모, 팀 구성, 인프라 환경에서 어떤 도구가 더 단순하고, 더 안정적이며, 운영이 쉬운가?

를 기준으로 선택하는 것입니다.


image

6. 마무리: 도구보다 “상황”이 먼저다

리눅스에서 웹 애플리케이션을 배포할 때, “무조건 Docker”도 아니고, “Docker는 나쁘고 systemd가 좋다”도 아닙니다.

  • 단일 서비스, 단순 인프라, 규제가 강한 환경 → systemd.service 배포가 더 현실적일 수 있고
  • 멀티 서비스, 다양한 환경, 빈번한 배포/스케일링 → Docker 기반 배포가 더 큰 가치를 줍니다.

이미 리눅스 서버를 사용하고 있다면, 한 번쯤은:

  • “이 서비스는 Docker가 꼭 필요할까?”
  • “systemd로 올리면 오히려 더 단순해지지 않을까?”

를 진지하게 고민해 볼 만합니다. 도구는 목적을 달성하기 위한 수단일 뿐이고, 단순함과 운영 용이성이 결국 장기적으로 가장 큰 생산성을 만들어 줍니다.