ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • systemd 완벽 정복 : 유닛(Unit)부터 systemctl 명령어까지
    임베디드 개발 환경 이야기 2025. 9. 15. 14:27

    지난 포스팅에서는 모든 프로세스의 시작점인 init 시스템에 대해 배우며, 낡은 SysVinit을 대체한 현대적인 systemd가 왜 등장했는지 알아보았습니다.
    systemd가 '스마트 팩토리'처럼 병렬 처리와 효율적인 의존성 관리로 부팅 속도를 획기적으로 개선했다는 점을 기억하실 겁니다.

    오늘은 이 강력한 '스마트 팩토리'의 내부로 들어가, 그 설계 철학은 무엇인지, 그리고 우리는 이 공장을 어떻게 제어하고 원하는 기계를 들여놓을 수 있는지, 즉 systemd를 실제로 어떻게 사용하고 활용하는지에 대해 집중적으로 알아보겠습니다.


    Part 1. systemd의 핵심 철학, 유닛(Unit)

    systemd를 이해하기 위한 가장 첫 번째 관문은 바로 유닛(Unit)이라는 개념입니다.

    systemd는 자신이 관리하는 모든 대상을 '유닛'이라는 표준화된 단위로 취급합니다.
    서비스, 마운트 포인트, 소켓, 심지어는 특정 시스템 상태까지도 모두 유닛으로 정의됩니다.

    비유: 시스템을 조립하는 '레고(LEGO) 블록'

    systemd의 유닛은 레고 블록과 같습니다. 각 블록(유닛)은 모양과 역할이 다릅니다.

    • service 유닛: 엔진이나 모터 같은 '동작' 블록
    • socket 유닛: 센서나 버튼 같은 '입력' 블록
    • target 유닛: 여러 블록을 모아 만든 '자동차의 차체' 같은 중간 조립품

    우리는 이 표준화된 레고 블록들을 조립 설명서(설정 파일)에 따라 연결하여,
    '자동차'라는 하나의 완성된 시스템을 만들어냅니다.

    가장 자주 만나게 될 유닛의 종류는 다음과 같습니다.

    • *.service: 가장 기본적이고 중요한 유닛. 데몬이나 애플리케이션 같은 백그라운드 서비스를 정의합니다. (예: network.service, my-avn-app.service)
    • *.socket: 네트워크 소켓이나 파일시스템 소켓을 정의합니다. 특정 소켓에 요청이 들어올 때만 연결된 .service 유닛을 활성화시키는 '온디맨드' 실행의 핵심입니다.
    • *.target: 여러 유닛을 논리적으로 그룹화하는 유닛입니다. SysVinit의 '런레벨'과 비슷한 역할을 하며, 특정 상태에 도달하기 위해 필요한 다른 유닛들의 의존성을 정의합니다. (예: multi-user.target, graphical.target)
    • *.mount: 파일 시스템의 마운트 포인트를 정의합니다.
    • *.timer: 특정 시간에 또는 주기적으로 잡(job)을 실행시키는 cron과 유사한 역할을 합니다.

    이처럼 모든 것을 '유닛'으로 표준화했기 때문에, 우리는 systemctl이라는 단 하나의 명령어로 시스템의 모든 구성요소를 일관되게 관리할 수 있습니다.


    Part 2. 내 손으로 서비스 만들기: 유닛 파일 작성법

    백문이 불여일견! systemd가 관리할 수 있도록, 우리의 AVN 메인 애플리케이션(my-avn-app)을 위한 .service 유닛 파일을 직접 만들어 보겠습니다.

    유닛 파일은 보통 /etc/systemd/system/ 디렉터리에 유닛이름.유닛타입 형식으로 만듭니다. (예: my-avn-app.service)

    파일 내용은 [섹션]키=값 형식으로 이루어진 간단한 텍스트 파일입니다.

    my-avn-app.service

    # 이 유닛에 대한 설명 (사람이 보기 위함)
    [Unit]
    Description=My Awesome AVN Main Application
    # 이 서비스는 네트워크와 사운드 시스템이 준비된 '이후에' 시작되어야 함
    After=network-online.target sound.target
    
    # 서비스의 실제 동작 방식 정의
    [Service]
    # 'simple'은 ExecStart 명령이 주 프로세스임을 의미 (가장 일반적)
    Type=simple
    # 서비스를 시작하기 위해 실행할 명령어
    ExecStart=/usr/bin/my-avn-app
    # 서비스가 비정상적으로 종료되면 자동으로 재시작
    Restart=on-failure
    
    # 이 유닛을 어떻게 시스템에 '설치'할 것인지 정의
    [Install]
    # 'systemctl enable' 명령을 사용했을 때, multi-user.target에 포함되도록 함
    # 즉, 일반적인 다중 사용자 모드로 부팅될 때 이 서비스를 시작하라는 의미
    WantedBy=multi-user.target

    각 섹션의 역할을 다시 정리해볼까요?

    • [Unit] 섹션 (이력서): 이 유닛이 누구이며, 다른 유닛과 어떤 관계(실행 순서)를 갖는지 정의합니다.
      • Description: 사람이 알아보기 쉬운 설명.
      • After=, Before=: 유닛 간의 실행 순서를 정의합니다. (가장 중요!)
      • Wants=, Requires=: 의존성을 정의합니다. (Requires는 더 강력한 의존성)
    • [Service] 섹션 (행동 지침): .service 유닛의 실제 동작 방식을 상세하게 정의합니다.
      • Type=: 서비스의 프로세스 타입. (simple, forking, oneshot 등)
      • ExecStart=: 서비스를 시작할 때 실행할 명령어. (필수!)
      • ExecStop=: 서비스를 중지할 때 실행할 명령어.
      • Restart=: 어떤 상황에서 서비스를 재시작할지 정의합니다. (on-failure, always 등) (안정성 확보의 핵심!)
    • [Install] 섹션 (소속 부서): systemctl enable/disable 명령을 통해 이 유닛이 어떤 target에 소속될지를 정의합니다.

    이제 이 파일만 /etc/systemd/system에 넣어주면, systemd는 우리의 my-avn-app을 하나의 정식 서비스로 인식하고 관리할 수 있게 됩니다!

    Part 3. 시스템을 지휘하는 마법 지팡이, systemctl

    유닛 파일을 만들었다면, 이제 systemctl 명령어로 시스템을 지휘할 차례입니다. systemctl은 systemd를 제어하는 가장 중요한 도구입니다.

    유닛의 라이프사이클 관리

    • systemctl start my-avn-app.service: 서비스를 즉시 시작합니다.
    • systemctl stop my-avn-app.service: 서비스를 즉시 중지합니다.
    • systemctl restart my-avn-app.service: 서비스를 재시작합니다.

    부팅 시 자동 실행 관리

    • systemctl enable my-avn-app.service: 부팅 시 자동으로 시작되도록 등록합니다. ([Install] 섹션의 WantedBy 설정을 사용)
    • systemctl disable my-avn-app.service: 자동 시작을 해제합니다.

    상태 확인 및 분석

    • systemctl status my-avn-app.service: 서비스의 현재 상태를 아주 상세하게 보여줍니다.
      (실행 중인지, 언제 시작했는지, PID는 무엇인지, 최근 로그는 어떤지 등 디버깅의 시작점!)
    • systemctl is-active my-avn-app.service: 서비스가 실행 중인지 여부만 간단히 확인합니다.
    • systemctl is-enabled my-avn-app.service: 부팅 시 자동 실행되도록 등록되어 있는지 확인합니다.

    ⚠️ 아주 중요한 팁!
    .service 파일을 수정했다면, 반드시 systemctl daemon-reload 명령어를 실행해야 systemd가 변경된 내용을 인식합니다. 이걸 잊어서 왜 적용이 안 되지? 하고 헤매는 경우가 정말 많습니다.

    Part 4. 모든 흔적을 기록하는 수사관, journalctl

    systemd는 journald라는 자체 로깅 시스템을 가지고 있습니다.
    과거처럼 여러 서비스가 /var/log 아래에 제각각 로그 파일을 남기는 대신, 모든 시스템 이벤트를 하나의 중앙화된 저널에 기록합니다.

    journalctl은 이 저널을 조회하는 강력한 도구입니다.

    • journalctl: 모든 로그를 시간순으로 보여줍니다.
    • journalctl -f: 새로운 로그가 기록될 때마다 실시간으로 보여줍니다. (마치 tail -f 처럼)
    • journalctl -b: 이번 부팅 이후의 로그만 보여줍니다. (부팅 문제 분석 시 필수)
    • journalctl -u my-avn-app.service: 특정 유닛(서비스)에 대한 로그만 필터링해서 보여줍니다. (가장 많이 사용하게 될 명령어!)
    • journalctl -p err: 에러(err) 등급 이상의 심각한 로그만 보여줍니다.

    journalctl 덕분에 우리는 더 이상 로그 파일을 찾아 헤맬 필요 없이, 원하는 조건으로 로그를 빠르고 정확하게 분석하여 버그의 원인을 찾아낼 수 있습니다.

    오늘은 systemd의 핵심 개념인 유닛(Unit)부터, .service 파일을 직접 작성하고 systemctl과 journalctl로 서비스를 제어하고 분석하는 방법까지 알아보았습니다.

    • systemd는 모든 것을 '유닛' 단위로 관리한다.
    • 우리는 .service 파일을 작성하여 우리의 앱을 시스템 서비스로 등록할 수 있다.
    • systemctl은 서비스의 시작, 중지, 자동 실행을 관리하는 제어 도구다.
    • journalctl은 시스템의 모든 로그를 분석하는 강력한 디버깅 도구다.

    이제 systemd는 더 이상 복잡하고 낯선 존재가 아니라, 우리 AVN 시스템의 부팅 시간을 최적화하고, 안정성을 높이기 위해 마음껏 활용할 수 있는 강력한 아군이 되었습니다.

Designed by Tistory.