LabHub

RHEL 계열 관리 · 모듈과 스트림 · 이론

모듈러리티와 module_hotfixes

LabHub 에서 이어서 보기

한 줄 요약

모듈러 RPM 은 일반 RPM 의존성 위에 얹힌 추가 계층을 갖는다. 그 계층 정보가 없으면 패키지가 파일로는 있는데 조회되지 않는다.

왜 이게 필요했나

폐쇄망에서 이런 신고가 온다.

ls /srv/repo/appstream/ | grep nodejs# nodejs-18.20.4-1.module+el9.4.0+21212+d9e3c1f2.x86_64.rpmdnf list available nodejs# No matching Packages to list

파일은 거기 있다. 그런데 dnf 는 없다고 한다. 에러도 안 난다.

어떻게 동작하나

왜 이런 일이 생기나

인과가 다섯 단계다.

1. dnf reposync 로 AppStream 을 받았는데 --download-metadata 를 붙이지 않았다
2. 패키지 파일은 다 왔지만 모듈 메타데이터는 오지 않았다
3. createrepo_c 는 rpm 파일에서 일반 메타데이터만 만든다. 모듈 데이터는 rpm 안에 없으므로 만들 수 없다
4. 안쪽 dnf 는 모듈러 RPM 을 보고도 어느 스트림 소속인지 모른다
5. 필터링 결과 그 패키지들이 조회되지 않는다

RHEL 9 문서는 모듈 의존성을 "일반 RPM 의존성 위의 추가 계층" 이라 표현하고, "저장소 사이의 가상적인 의존성처럼 동작한다" 고 설명한다.

버전별 차이

| 항목 | RHEL 8 | RHEL 9 | RHEL 10 |
| --- | --- | --- | --- |
| 모듈 제공 | AppStream 의 핵심 방식 | 9.1부터 수명주기가 짧은 추가 버전으로 | 공식 문서에 모듈 장이 없음 |
| 기본 스트림 | 있음 | 미리 정의된 기본 스트림 없음 | 해당 없음 |
| 스트림 지정 없이 설치 | 기본 스트림 자동 활성화 | 스트림을 지정해야 함 | 해당 없음 |
| 스트림 전환 | distro-syncmodule resetmodule enabledistro-sync | dnf module switch-to 한 줄 | 해당 없음 |

RHEL 8 에서 RHEL 9 로 오면서 모듈의 비중이 크게 줄었고, RHEL 10 에서는 사실상 사라졌다. 하지만 RHEL 8/9 시스템은 앞으로도 오래 남는다.

명령

dnf module listdnf module list nodejsdnf module info nodejs:20dnf module enable nodejs:20dnf module install nodejs:20/commondnf module reset nodejsdnf module switch-to nodejs:20      # RHEL 9dnf module list --installed > state-modules.txt

reset 은 활성화 상태를 초기화한다. 스트림을 바꾸려면 보통 reset 이 먼저다.

해법 세 갈래

방법 1 — 받을 때 함께 (정석)

dnf reposync --repoid=...appstream-rpms --download-path=/srv/sync \  --download-metadata --gpgcheck --arch=x86_64 --arch=noarch

이 경우 반입 후 createrepo_c다시 돌리면 안 된다. 돌리면 오히려 모듈 데이터를 잃는다.

방법 2 — dnf modulesync

모듈에 속한 패키지를 받으면서 모듈 데이터가 포함된 저장소를 만들어 준다.

dnf --destdir=/srv/bundle/nodejs modulesync nodejs:20/minimal --resolve

방법 3 — module_hotfixes=1 (마지막 수단)

[airgap-appstream]name=RHEL 9 AppStream (airgap, no modular metadata)baseurl=file:///srv/repo/appstreamenabled=1gpgcheck=1module_hotfixes=1metadata_expire=-1

문서상 정의: "모듈 RPM 필터링을 비활성화하고 저장소의 모든 RPM 을 사용 가능하게 한다. 기본값은 False."

대가가 있다. 서로 다른 스트림의 패키지가 섞여 설치될 수 있고, 그 조합은 Red Hat 이 시험한 조합이 아니다. 그래서 "마지막 수단" 이다.

installroot 를 쓸 때

빈 루트를 기준으로 계산할 때 모듈 플랫폼 ID 를 함께 지정해야 한다.

dnf download --installroot=/var/tmp/airgap-root --releasever=9.4 \  --setopt=module_platform_id=platform:el9 \  --resolve --alldeps --destdir=/srv/bundle nodejs

지정하지 않으면 그 값이 빈 루트의 /etc/os-release 에서 오는데, 생성 시점에는 그 파일이 없어 값이 비고 모듈 콘텐츠가 에러 없이 통째로 빠진다. 조용히 빠지기 때문에 가장 발견하기 어려운 종류의 사고다.

grep PLATFORM_ID /etc/os-release# PLATFORM_ID="platform:el9"

현장에서 만나는 모습

상태 기록 4종. 반입 전후에 이 네 가지를 남겨 두면 조사가 훨씬 쉬워진다.

dnf module list --installed > state-modules.txtrpm -qa --qf '%{NAME}\t%|EPOCH?{%{EPOCH}}:{0}|\t%{VERSION}\t%{RELEASE}\t%{ARCH}\n' | sort > state-packages.tsvdnf history userinstalled > state-userinstalled.txtdnf history list > state-history.txt

세 번째가 특히 유용하다. 사용자가 명시적으로 설치한 것만 나오므로, 그 목록만 다른 서버에서 설치하면 의존성은 알아서 따라온다. 전체 패키지 목록을 그대로 밀어 넣는 것보다 훨씬 안전하다.

다음 확인에서 볼 것

이 모듈은 개념을 판단하는 퀴즈로 마친다. 모듈 메타데이터가 빠졌을 때 나타나는
증상과 module_hotfixes의 위험 범위를 구분한 뒤, 다음 모듈의 rh-createrepo
rh-airgap 실습에서 저장소 복제 방식을 선택한다.