systemd 유닛 파일 — 서비스 정의의 모든 것

[Unit], [Service], [Install] 세 섹션의 구조, 의존성 지시어(After/Requires/Wants), Type과 Restart 옵션, override.conf 활용법을 설명합니다.

· 4 min read · PALDYN Team

지난 글에서 systemctl로 서비스를 제어하는 방법을 배웠습니다. 이번에는 서비스를 정의하는 유닛 파일을 직접 작성하고 수정하는 방법을 다룹니다. 자신만의 서비스를 systemd로 관리하거나 기존 서비스 설정을 튜닝할 때 유닛 파일을 이해하는 것이 필수입니다.

유닛 파일의 세 섹션

유닛 파일은 INI 형식으로 세 섹션으로 나뉩니다.

유닛 파일 구조

[Unit]       # 서비스 설명과 의존성
[Service]    # 실행 방법과 재시작 정책
[Install]    # enable 시 연결할 타겟

[Unit] 섹션 — 의존성 제어

[Unit]
Description=My Application Service
After=network.target postgresql.service
Requires=postgresql.service
Wants=redis.service

의존성 지시어 비교:

지시어의미
After=순서만 지정 (저것이 먼저 시작된 후)
Requires=강한 의존성 (저것이 실패하면 나도 중단)
Wants=약한 의존성 (저것이 없어도 나는 계속)
BindsTo=Requires보다 강함 (저것이 중단되면 나도 즉시 중단)

After=는 시작 순서만 제어하고, 의존성 자체는 Requires=Wants=로 별도 설정해야 합니다. 둘을 함께 쓰는 경우가 많습니다.

[Service] 섹션 — 실행 설정

[Service]
Type=simple
User=appuser
Group=appgroup
WorkingDirectory=/opt/myapp
EnvironmentFile=/etc/myapp/env
ExecStartPre=/opt/myapp/check-config.sh
ExecStart=/opt/myapp/bin/server --port 8080
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5

ExecStart 주의사항:

# ✓ 절대 경로 필수
ExecStart=/usr/bin/node /opt/app/server.js

# ✓ 환경변수는 EnvironmentFile 로
EnvironmentFile=/etc/myapp/.env
ExecStart=/usr/bin/python3 /opt/app/main.py

# ✗ 쉘 기능(파이프, &&)은 직접 사용 불가
ExecStart=/bin/foo | /bin/bar   # 오류

# ✓ 쉘 기능이 필요하면
ExecStart=/bin/bash -c "/bin/foo | /bin/bar"

서비스 Type과 Restart 옵션

[Install] 섹션 — 활성화 설정

[Install]
WantedBy=multi-user.target

systemctl enable이 실행하면 /etc/systemd/system/multi-user.target.wants/myapp.service 심볼릭 링크를 만듭니다. 이 링크가 있으면 multi-user.target이 활성화될 때 이 서비스도 함께 시작합니다.

실전: 나만의 서비스 만들기

# 1. 유닛 파일 작성
sudo nano /etc/systemd/system/myapp.service
[Unit]
Description=My Python App
After=network.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/opt/myapp
EnvironmentFile=/opt/myapp/.env
ExecStart=/usr/bin/python3 server.py
Restart=on-failure
RestartSec=3

[Install]
WantedBy=multi-user.target
# 2. systemd에 알리기
sudo systemctl daemon-reload

# 3. 활성화 및 시작
sudo systemctl enable --now myapp

# 4. 확인
systemctl status myapp

override.conf — 원본 파일 수정 없이 덮어쓰기

패키지가 제공한 유닛 파일을 직접 수정하면 패키지 업데이트 시 덮어씌워집니다. systemctl edit으로 override.conf를 만들면 원본은 유지됩니다.

# override.conf 편집기 열기
sudo systemctl edit nginx

# 에디터에 입력
[Service]
LimitNOFILE=65536
Environment="CUSTOM_VAR=value"

# 저장하면 /etc/systemd/system/nginx.service.d/override.conf 생성
# 설정 확인 (원본 + override 병합 결과)
systemctl cat nginx

override.conf는 원본 파일의 같은 섹션 설정을 추가합니다. 기존 값을 완전히 교체하려면 먼저 빈 값으로 초기화한 뒤 새 값을 설정해야 합니다.

# ExecStart 교체 예시
[Service]
ExecStart=          # 기존 ExecStart 제거
ExecStart=/usr/bin/nginx -g 'daemon off;'  # 새 값

유용한 보안 설정

[Service]
# 불필요한 기능 차단
NoNewPrivileges=true
PrivateTmp=true          # 격리된 /tmp 사용
ProtectSystem=strict     # /usr, /boot, /etc 읽기 전용
ProtectHome=true         # 홈 디렉터리 접근 차단
ReadWritePaths=/var/lib/myapp  # 쓰기 허용 경로 명시

이 설정들은 서비스가 침해당해도 피해를 최소화합니다. 새 서비스를 만들 때 기본으로 추가하는 것이 좋은 습관입니다.


지난 글: systemctl 기본 — 서비스 관리의 핵심

다음 글: systemd 타겟 — 런레벨의 현대적 대체


읽어주셔서 감사합니다. 😊