Yocto recipe에 systemd 서비스, 어떻게 설치하나

Yocto systemd recipe로 앱 유닛을 넣으려면 세 가지만 맞추면 됩니다. (1) recipe에서 inherit systemdSYSTEMD_SERVICE, (2) do_install에서 유닛 파일을 ${D}${systemd_system_unitdir}(또는 ${D}${systemd_unitdir}/system)에 설치, (3) 배포판/이미지 쪽에서 systemd init을 켭니다. 이 글은 공식 systemd 클래스·init manager 문서 기준의 최소 howto입니다. 회사 전용 레이어·가격 이야기는 없습니다.

어떤 inherit?

한 줄 답: 유닛을 패키징하는 recipe에 inherit systemd를 넣고, SYSTEMD_SERVICE:${PN}에 서비스 파일 이름을 적습니다. 클래스 동작은 DISTRO_FEATURES에 systemd가 있을 때만 살아 있습니다.

Yocto Project Reference Manual의 systemd class 요지:

  • inherit systemd
  • SYSTEMD_SERVICE:${PN} = "mydaemon.service" (공백으로 여러 개 가능)
  • 기본으로 부팅 시 enable. 끄려면 SYSTEMD_AUTO_ENABLE:${PN} = "disable"
  • 유닛이 메인 패키지가 아니면 SYSTEMD_PACKAGES로 패키지를 지정

최소 recipe 골격:

SUMMARY = "Example daemon with systemd unit"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

SRC_URI = "file://mydaemon.service"

inherit systemd

SYSTEMD_SERVICE:${PN} = "mydaemon.service"
# SYSTEMD_AUTO_ENABLE:${PN} = "enable"  # default

do_install() {
    install -d ${D}${systemd_system_unitdir}
    install -m 0644 ${WORKDIR}/mydaemon.service ${D}${systemd_system_unitdir}/
}

connman 등 OE 예시도 SYSTEMD_SERVICE:${PN} = "connman.service" 형태입니다. 구식 SYSTEMD_SERVICE_${PN} 밑줄 문법은 새 릴리스에서는 : 오버라이드를 쓰는 편이 안전합니다.

파일은 어디에?

한 줄 답: do_install에서 유닛을 ${D}${systemd_system_unitdir} 아래 두세요. 문서는 ${D}${systemd_unitdir}/system으로도 설명합니다. 클래스와 검색 경로가 그 위치를 전제로 FILES·프리셋·패키지 스크립트를 채웁니다.

실무 체크:

  1. SRC_URIfile://foo.service를 넣고 WORKDIR에서 설치합니다.
  2. 설치 경로를 틀리면 packaging 단계에서 Didn't find service unit '…'fatal 납니다(systemd.bbclass 검색 실패).
  3. 템플릿 유닛(foo@.service)도 SYSTEMD_SERVICE에 이름을 맞추고, 인스턴스 enable은 클래스 프리셋 규칙을 따릅니다.
  4. user 유닛이 필요하면 클래스·검색 경로가 system/user를 나누므로, 문서/클래스 주석의 user unitdir을 확인합니다(대부분 보드 데몬은 system 유닛).

예시 유닛:

[Unit]
Description: Example daemon
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/mydaemon
Restart=on-failure

[Install]
WantedBy=multi-user.target

바이너리 경로는 recipe의 bindir 설치 위치와 일치시켜야 합니다.

IMAGE 기능 플래그는?

한 줄 답: systemd 선택은 보통 IMAGE_FEATURES가 아니라 배포/설정단의 INIT_MANAGER = "systemd"(또는 동등한 DISTRO_FEATURES/VIRTUAL-RUNTIME_init_manager)입니다. recipe의 inherit systemd만으로는 이미지 init이 systemd가 되지 않습니다.

Selecting an Initialization Manager 기준:

# distro conf 또는 local.conf
INIT_MANAGER = "systemd"

이렇게 하면 systemd가 켜지고 sysvinit 구성 요소가 빠지는 방향의 init-manager-systemd include가 잡습니다. 구형 문서/블로그에 보이던 수동 세트는 대략 다음 축입니다.

DISTRO_FEATURES:append = " systemd"
VIRTUAL-RUNTIME_init_manager = "systemd"
# 필요 시 DISTRO_FEATURES에서 sysvinit 정리

정리 표:

목적어디서무엇
유닛 패키징recipeinherit systemd, SYSTEMD_SERVICE
유닛 파일 위치do_install${D}${systemd_system_unitdir}
이미지 initdistro / local.confINIT_MANAGER = "systemd"
클래스 활성화DISTRO_FEATURESsystemd feature 필요

이미지 recipe에 앱 패키지가 들어가 있는지도 확인합니다(IMAGE_INSTALL / packagegroup). init만 systemd여도 패키지를 안 넣으면 유닛은 루트fs에 없습니다.

마무리

Yocto systemd recipeinherit systemd + SYSTEMD_SERVICE:${PN} + 올바른 unitdir 설치가 한 세트이고, 이미지 쪽은 **INIT_MANAGER = "systemd"**로 init을 고릅니다. 자세한 변수는 systemd class, init 선택은 Initialization Manager를 보시면 됩니다.

출처