systemd Unit 파일에서 WantedBy와 RequiredBy 개념 이해

조회수: 0

Unit 파일과 의존성 관계 기본 구조

systemd는 모든 것을 유닛이라는 단위로 관리한다. 서비스 파일인 something.service뿐 아니라 타깃인 multi-user.target, 타이머, 소켓 등도 모두 유닛이다.
이 유닛들 사이를 연결하는 핵심 개념이 의존성이다.

의존성은 크게 두 위치에서 정의된다.

  • [Unit] 섹션의 Requires Wants 등
  • [Install] 섹션의 RequiredBy WantedBy 등

[Unit] 섹션은 런타임 시점에 systemd가 실제로 유닛을 어떻게 함께 움직일지를 정의한다.
반면 [Install] 섹션은 systemctl enable 명령을 실행할 때 어떤 심볼릭 링크를 만들지, 즉 유닛을 어떻게 부팅 시나 특정 타깃에 연결할지를 정의한다.(freedesktop.org)

여기서 WantedBy와 RequiredBy는 둘 다 [Install] 섹션에만 사용된다.

Wants Requires와 WantedBy RequiredBy 관계

먼저 이름이 비슷한 Wants Requires를 짚고 넘어가면 전체 구조를 이해하기 쉽다.

  • A 유닛이 B 유닛을 Wants
    • A를 시작하면 B도 같이 시작하려고 시도한다
    • B가 실패해도 A는 계속 동작한다
  • A 유닛이 B 유닛을 Requires
    • A를 시작하면 B도 반드시 같이 시작해야 한다
    • B가 시작에 실패하면 A도 실패로 간주되고 멈춘다(Server Fault)

WantedBy RequiredBy는 이 관계를 반대 방향에서 기술하는 설치용 옵션이다.

  • X 유닛에 WantedBy=Y.target을 쓰면
    • systemctl enable X 실행 시
    • Y.target.wants 디렉터리 아래에 X에 대한 심볼릭 링크가 만들어진다
    • 결과적으로 Y.target이 X를 Wants 하는 의존성이 생긴다(freedesktop.org)
  • X 유닛에 RequiredBy=Y.target을 쓰면
    • systemctl enable X 실행 시
    • Y.target.requires 디렉터리 아래에 X에 대한 심볼릭 링크가 만들어진다
    • 결과적으로 Y.target이 X를 Requires 하는 강한 의존성이 생긴다(freedesktop.org)

즉 WantedBy RequiredBy는 자신을 다른 유닛에 의존성으로 연결하는 일종의 설치 스크립트 역할을 한다고 보면 된다.

WantedBy가 만드는 느슨한 의존성

실무에서 가장 흔히 보이는 설정이 바로 다음과 같은 패턴이다.

[Unit]
Description=예시 애플리케이션 서비스

[Service]
ExecStart=/usr/local/bin/example-app

[Install]
WantedBy=multi-user.target

이 경우 동작은 이렇게 정리할 수 있다.

  • systemctl enable example-app
    • multi-user.target.wants 디렉터리에 example-app.service 심볼릭 링크 생성
    • multi-user.target이 올라갈 때 example-app도 함께 시작 대상에 포함
  • example-app이 시작에 실패하더라도
    • multi-user.target 전체는 계속 진행
    • 시스템 부팅이 이 서비스 하나 때문에 멈추지 않는다(DigitalOcean)

즉 WantedBy는

  • 부팅 때 같이 올리기는 하되
  • 실패해도 타깃 전체에는 큰 영향을 주지 않는
  • 부가적인 서비스에 적합한 느슨한 의존성이다

로그 수집기, 모니터링 에이전트, 캐시 서버, 선택적인 백그라운드 작업 등에 잘 어울린다.

RequiredBy가 만드는 강한 의존성

RequiredBy는 이름 그대로 해당 타깃이나 서비스가 이 유닛을 필수 요소로 간주하게 만든다.

예를 들어 다음과 같이 작성했다고 해 보자.

[Unit]
Description=핵심 인증 서비스

[Service]
ExecStart=/usr/local/bin/core-authd

[Install]
RequiredBy=multi-user.target

이 설정을 enable 하면 multi-user.target.requires 디렉터리에 심볼릭 링크가 만들어지고, 결과적으로 multi-user.target이 core-authd.service를 Requires 하게 된다.(freedesktop.org)

이때 동작은 다음과 같이 달라진다.

  • multi-user.target이 올라갈 때 core-authd는 반드시 함께 시작되어야 한다
  • core-authd가 시작에 실패하면 multi-user.target의 활성화도 실패 상태가 된다
  • 나중에 core-authd를 중지하면 multi-user.target에 딸린 다른 서비스들이 연쇄적으로 중지될 수 있다

즉 RequiredBy는 전체 타깃을 좌우할 정도로 중요한 서비스에만 사용해야 한다.
인증, 필수 스토리지, 핵심 네트워크 구성처럼 이 서비스 없이는 시스템이 의미 있게 동작할 수 없는 경우가 대표적이다.

실전 예제로 보는 설정 패턴

조금 더 현실적인 예를 들어 보자.

1 웹 애플리케이션 서비스

  • nginx를 프론트로 두고 뒤에서 app.service가 동작한다고 가정하자
  • nginx가 없어도 서버에 ssh로 접속해서 트러블슈팅은 가능하다

이 경우 app.service에는 보통 이렇게 설정한다.

[Install]
WantedBy=multi-user.target

애플리케이션이 죽는다고 해서 시스템 전체를 장애로 판단하고 싶지는 않기 때문이다.

2 필수 스토리지 마운트 유닛

  • /data를 마운트하지 못하면 그 위에 올라가는 거의 모든 서비스가 의미가 없다고 가정하자

이때는 다음처럼 RequiredBy를 고려할 수 있다.

[Install]
RequiredBy=multi-user.target

이렇게 하면 /data 마운트 유닛이 실패할 경우 multi-user.target 자체가 실패 상태가 되며, 모니터링 시스템에서 부팅 실패나 심각한 장애로 인식하기 쉬워진다.

자주 나오는 오해와 주의점

실무에서 자주 나오는 오해들을 정리해 보자.

첫째 WantedBy와 RequiredBy만으로 순서를 제어할 수 있다고 생각하는 경우가 많다.
하지만 이 둘은 어디까지나 어떤 타깃이 어떤 서비스를 끌어오는지 정의할 뿐, 시작 순서는 After Before 옵션이 담당한다.(Server Fault)

둘째 RequiredBy를 남용하면 시스템이 쉽게 부팅 실패 상태에 빠질 수 있다.
조금만 불안정한 서비스라도 RequiredBy로 묶어 두면, 이 서비스의 일시적인 실패가 시스템 전체를 장애로 보이게 만들 수 있다.

셋째 Wants와 WantedBy를 뒤섞어 쓰는 경우

  • A 서비스의 [Unit]에 Wants=B.service
  • B 서비스의 [Install]에 WantedBy=A.service
    처럼 양쪽에 모두 관계를 적어 두는 패턴이 종종 보이는데, 기능상 중복인 경우가 대부분이다.(Unix & Linux Stack Exchange)

의존성이 꼬이기 쉬우니 가능한 한 한쪽 방향으로만 기술하는 것이 유지보수에 유리하다.

언제 WantedBy를 쓰고 언제 RequiredBy를 쓸지 정리

마무리로 선택 기준을 정리해 보자.

1 이 서비스가 실패해도 타깃이나 시스템 전체는 계속 올라와야 하는가

  • 예 라면 WantedBy를 사용한다
  • 모니터링 에이전트, 로그 수집기, 캐시, 부가기능 서비스 등에 해당

2 이 서비스가 없으면 해당 타깃의 존재 의미가 거의 사라지는가

  • 예 라면 RequiredBy를 진지하게 검토할 수 있다
  • 필수 스토리지, 핵심 인증 서비스, 보안상 반드시 필요한 방화벽 구성 등

3 애매할 때의 기본값

  • 대부분의 배포판과 튜토리얼이 기본 예제로 WantedBy=multi-user.target을 사용한다(DigitalOcean)
  • 따라서 특별한 이유가 없다면 WantedBy를 기본으로 생각하고
  • 진짜로 타깃 전체가 이 서비스에 강하게 의존해야 할 때만 RequiredBy를 도입하는 편이 안전하다

정리하면 WantedBy와 RequiredBy는 기능 자체는 비슷하지만 실패 전파와 장애 인식 수준이 크게 다르다.
유닛이 시스템에서 차지하는 역할과 중요도를 먼저 정의한 뒤, 그에 맞춰 WantedBy로 느슨하게 연결할지 RequiredBy로 강하게 묶을지를 선택하는 것이 systemd 환경을 안정적으로 운영하는 핵심 포인트다.