베어메탈 설치를 전제로 만들어진 RPM 을 이미지 빌드 중에 설치하면 사전 스크립트가 systemd 를 찾다가 실패한다.
Running scriptlet: plexmediaserver-1.42.2.10156-f737b826c.x86_64
Plex Media Server requires systemd. Please upgrade the Operating System version
error: %prein(plexmediaserver-...) scriptlet failed, exit status 1
컨테이너 이미지에는 PID 1 로 도는 systemd 가 없다. 서비스 등록·기동을 전제로 한 %pre · %post 스크립트는 그래서 실패하거나, 실패하지 않더라도 아무 의미 없는 유닛 파일만 남긴다.
대부분의 제품은 컨테이너용 이미지를 따로 배포한다. 이쪽은 systemd 대신 포어그라운드 실행을 전제로 만들어져 있어 위 문제가 없다. 직접 만들 이유가 없으면 이 선택지를 먼저 본다.
RPM 은 설치하되 서비스 등록 스크립트는 돌리지 않는 방법이다. 가볍고 컨테이너 관례에도 맞는다.
FROM rockylinux:9
RUN dnf -y install curl tar xz && dnf clean all
RUN curl -L -o /tmp/app.rpm https://example.com/app-1.0.x86_64.rpm \
&& rpm -i --noscripts /tmp/app.rpm \
&& rm -f /tmp/app.rpm
EXPOSE 32400
CMD ["/usr/lib/app/app-binary"]
--noscripts 는 사용자·그룹 생성이나 디렉터리 권한 설정 같은 필요한 작업까지 건너뛴다. rpm -qp --scripts app.rpm 으로 어떤 스크립트가 들어 있는지 먼저 보고, 빠지는 부분은 Dockerfile 에서 useradd · mkdir · chown 으로 직접 채운다. 필요한 것만 남기려면 --noscripts 대신 --nopre 나 --noposttrans 로 좁힐 수도 있다.
패키지 구조상 systemd 가 정말 필요하면 이미지 안에서 systemd 를 PID 1 로 돌린다. 이미지가 무거워지고 cgroup 권한 때문에 실행 옵션이 까다로워지므로 마지막 수단이다.
FROM rockylinux:9
RUN dnf -y install systemd systemd-libs dbus && dnf clean all
STOPSIGNAL SIGRTMIN+3
CMD ["/usr/sbin/init"]
실행할 때 cgroup 파일 시스템 접근이 필요하다. Podman 은 systemd 이미지를 감지해 필요한 설정을 자동으로 잡아 주므로 이 용도에는 Podman 쪽이 다루기 쉽다.
미디어 서버처럼 하드웨어를 쓰는 애플리케이션은 장치 노드를 컨테이너로 넘겨야 한다. Intel Quick Sync 는 /dev/dri, USB 장치는 /dev/bus/usb 다. 장치를 넘기지 않은 상태에서 나오는 libusb_init failed 같은 메시지는 해당 기능을 쓰지 않는다면 무시해도 된다.
services:
app:
image: example/app:latest
devices:
- /dev/dri:/dev/dri