RHEL 기초 #3 dnf와 패키지 관리 — repo, modules, AppStream

10 분 소요

#2에서 RHEL 머신을 띄우고 등록까지 마쳤습니다. 이제 이 위에 무언가를 깔고 지우는 일을 다룰 차례입니다. RHEL의 패키지 관리는 dnf 한 명령으로 통합니다. 우분투의 apt와 같은 역할입니다.

RHEL 기초 시리즈에서 이번 글의 위치:

rpm / yum / dnf — 한 줄 정리 #

먼저 헷갈리는 세 단어부터 정리해 둡니다.

도구다루는 것설명
rpm.rpm 파일 한 장의존성 자동 해결 안 됨. 직접 받은 .rpm을 설치할 때만 가끔 씀.
yum저장소 + 의존성RHEL 5~7의 표준. RHEL 8부터는 사실상 dnf의 별명.
dnf저장소 + 의존성 + modulesRHEL 8부터 표준. 파이썬으로 다시 쓴 yum.

RHEL 9에서는 yum 명령어를 쳐도 동작하긴 합니다. 그냥 dnf로 심볼릭 링크돼 있습니다. 새 자료를 검색하거나 새 명령(dnf module)을 쓰려면 dnf로 통일하는 편이 좋습니다.

확인
$ which yum
/usr/bin/yum
$ ls -l /usr/bin/yum
lrwxrwxrwx. 1 root root 5 ... /usr/bin/yum -> dnf-3

dnf의 일상 명령군 #

가장 자주 만나는 명령부터.

검색 — search / info / list #

패키지 찾기
$ dnf search nginx
=================== Name & Summary Matched: nginx ===================
nginx.aarch64 : A high performance web server and reverse proxy server
nginx-mod-http-image-filter.aarch64 : Nginx HTTP image filter module
...

$ dnf info nginx
Name         : nginx
Version      : 1.20.1
Release      : 20.el9
Architecture : aarch64
Size         : 593 k
Source       : nginx-1.20.1-20.el9.src.rpm
Repository   : rhel-9-for-aarch64-appstream-rpms
Summary      : A high performance web server and reverse proxy server
URL          : https://nginx.org
License      : BSD
Description  : ...

info가 검색보다 정보가 많아 더 자주 봅니다. Repository 항목으로 어느 저장소에서 오는지 알 수 있습니다 — 위에서는 AppStream 저장소.

목록
$ dnf list installed | head           # 설치된 패키지
$ dnf list available nginx*           # 설치 가능한 패키지
$ dnf list updates                    # 업데이트 가능한 패키지

설치 — install #

설치
$ sudo dnf install nginx
Dependencies resolved.
============================================================
 Package                Arch     Version           Repository      Size
============================================================
Installing:
 nginx                  aarch64  1:1.20.1-20.el9   appstream      593 k
Installing dependencies:
 nginx-filesystem       noarch   1:1.20.1-20.el9   appstream       11 k
 ...

Transaction Summary
============================================================
Install  6 Packages

Total download size: 1.3 M
Installed size: 4.2 M
Is this ok [y/N]:

여러 개를 한 번에 설치할 수 있고 (dnf install nginx git vim), 의존성도 자동으로 끌고 옵니다. 자동 yes가 필요하면 -y를 붙여요. 자동화 스크립트에서는 자주 쓰지만, 수동 작업에서는 의존성 목록을 한 번 보고 결정하는 습관이 좋습니다.

로컬 .rpm 설치
$ sudo dnf install ./some-package.rpm

다운로드한 단일 .rpm 파일도 dnf install로 설치하면 의존성을 자동으로 해결합니다. rpm -i보다 거의 항상 이쪽이 정답입니다.

제거 — remove #

제거
$ sudo dnf remove nginx
Dependencies resolved.
=========================================================
Removing:
 nginx              ...
Removing unused dependencies:
 nginx-filesystem   ...

설치할 때 같이 끌려온 의존성도 다른 곳에서 안 쓰면 자동 정리됩니다 (autoremove 동작 내장). 우분투에서 apt remove + apt autoremove 두 번 쳐야 하는 걸 한 번에 정리합니다.

함정dnf remove가 핵심 패키지 (예: systemd, kernel) 를 같이 지우려 들면 즉시 멈추고 입력 확인을 다시 보세요. 의존성이 사방으로 얽힌 곳에선 패키지 하나 지우다 시스템이 부팅 불가가 되기도 합니다. 모르는 의존성 목록은 항상 멈춰 읽습니다.

업데이트 — update / upgrade #

업데이트
$ sudo dnf check-update           # 업데이트 가능한 것만 보기 (변경 없음)
$ sudo dnf update                 # 모든 패키지 최신으로
$ sudo dnf update nginx           # 한 패키지만

updateupgrade는 RHEL/dnf에서 사실상 같은 동작입니다 (다른 배포판에선 다를 수 있음). 보통 update를 더 많이 써요.

의존성 추적 — repoquery #

깊이 들어갈 때 자주 쓰는 명령입니다.

repoquery
$ dnf repoquery --requires nginx       # nginx가 의존하는 것
$ dnf repoquery --whatrequires nginx   # nginx를 의존하는 것
$ dnf repoquery -l nginx               # 패키지가 설치하는 파일 목록
$ dnf repoquery --provides nginx       # 패키지가 제공하는 가상 이름

특히 dnf repoquery -l <패키지> — 어떤 패키지가 무슨 파일을 깔았는지 추적할 때 손이 자주 갑니다.

dnf history — 시간을 되돌리는 명령 #

가장 RHEL 다운 기능. 모든 dnf 트랜잭션이 이력으로 남고, 트랜잭션 단위로 되돌릴 수 있습니다.

이력 보기
$ sudo dnf history
ID  | Command line          | Date and time    | Action(s)   | Altered
----------------------------------------------------------------------
 12 | install nginx          | 2026-04-11 14:23 | Install     |    6
 11 | update -y              | 2026-04-11 09:01 | I, U        |   42
 10 | install git vim        | 2026-04-10 17:45 | Install     |    8
  9 | system upgrade ...     | 2026-04-10 16:02 | Install     |  362
이력 한 건 자세히
$ sudo dnf history info 12
Transaction ID : 12
Begin time     : 2026-04-11 14:23:08
Command Line   : install nginx
Packages Altered:
    Install nginx-1:1.20.1-20.el9.aarch64        @appstream
    Install nginx-filesystem-1:1.20.1-20.el9.noarch  @appstream
    ...
되돌리기 / 다시 적용
$ sudo dnf history undo 12      # 12번 트랜잭션 되돌리기
$ sudo dnf history redo 12      # 다시 적용

운영에서 가장 손이 자주 가는 명령은 **장애 직후의 dnf history**입니다. “방금 뭘 바꿨더라?“라는 질문의 답이 거기 있습니다. apt에는 없는 기능입니다.

BaseOS와 AppStream — 두 저장소가 갈린 이유 #

#2에서 dnf repolist를 쳐 보면 두 줄이 나왔습니다.

저장소 목록
$ dnf repolist
repo id                               repo name
rhel-9-for-aarch64-appstream-rpms     Red Hat Enterprise Linux 9 - AppStream
rhel-9-for-aarch64-baseos-rpms        Red Hat Enterprise Linux 9 - BaseOS

두 저장소가 따로 있는 데는 의도가 있습니다.

BaseOS — 변하지 않는 OS 코어 #

BaseOS의 모양
커널 / glibc / systemd / coreutils / openssl / NetworkManager
        ↑ OS가 OS답게 동작하는 데 꼭 필요한 부품

RHEL 9의 라이프사이클(10년) 동안 메이저 버전이 거의 바뀌지 않습니다. 보안 패치만 받습니다. “운영 중인 시스템의 안정성"이 BaseOS의 약속입니다.

AppStream — 빠르게 변할 수 있는 응용 패키지 #

AppStream의 모양
PostgreSQL / Python / Node.js / nginx / Apache / Redis / Ruby / PHP / ...
        ↑ 사람이 골라 까는 응용 / 언어 / DB / 서버

여기서는 같은 RHEL 9 안에서도 다른 메이저 버전들을 골라 설치할 수 있습니다. PostgreSQL 13 / 15 / 16, Python 3.9 / 3.11 / 3.12 이런 식으로. 이걸 가능하게 하는 게 modules.

이 분리는 RHEL 8부터 도입된 AppStream 컨셉입니다. RHEL 7 까지는 한 패키지에 한 메이저 버전만 가능해서 PostgreSQL 새 버전을 쓰려면 외부 저장소(postgresql.org의 PGDG repo) 를 붙여야 했습니다. AppStream 이후로는 RHEL 공식 저장소 안에서 골라 쓸 수 있게 됐습니다.

dnf module — 같은 패키지의 여러 버전 #

PostgreSQL을 예로 들어봅시다.

모듈 목록
$ dnf module list postgresql
Red Hat Enterprise Linux 9 for aarch64 - AppStream
Name         Stream    Profiles                  Summary
postgresql   13        client, server [d]        PostgreSQL server and client module
postgresql   15        client, server [d]        PostgreSQL server and client module
postgresql   16        client, server [d]        PostgreSQL server and client module

세 가지 메이저 버전이 보입니다. 각 버전 옆 Stream이 그 버전의 식별자고, Profile은 “어떤 용도로 설치할지"를 미리 묶어둔 세트입니다.

특정 버전 활성화 + 설치
$ sudo dnf module enable postgresql:16
$ sudo dnf module install postgresql:16/server

postgresql:16으로 모듈 stream을 활성화하고, postgresql:16/server로 server profile을 설치합니다. 활성화된 stream은 시스템에 한 번에 하나만 둘 수 있습니다. 같은 머신에 PG 13과 PG 16을 동시에 두지는 못합니다 (그건 컨테이너로).

모듈 정보 확인 / 비활성화
$ dnf module info postgresql:16
$ sudo dnf module disable postgresql        # 모든 stream 비활성화 (제거 전)
$ sudo dnf module reset postgresql          # 활성화 / 비활성화 모두 초기화

어떤 stream을 골라야 하나 #

default가 표시된 ([d]) stream을 그냥 따라가는 게 가장 무난합니다. RHEL 9에 들어 있는 그 stream은 RHEL의 라이프사이클 끝까지 (또는 모듈에 따라 5 년) 패치를 보장합니다.

특정 버전을 명시적으로 잡고 싶을 때만 stream을 골라 활성화. 한 번 stream을 정해두면 dnf update가 그 stream 안에서 마이너 업데이트만 적용해 — 어느 날 갑자기 PG 16이 PG 17로 점프하지 않습니다.

2026년 노트 — 사용자 패턴을 보고 RHEL 10부터 modules의 비중이 줄어들 거라는 신호가 있습니다. 새 RHEL일수록 “default stream"만 있는 모듈도 늘고 있는데, 그래도 RHEL 9에서는 modules가 핵심에 있습니다.

외부 저장소 — EPEL, COPR #

RHEL 공식 저장소 (BaseOS + AppStream) 에 없는 패키지가 필요할 때 두 가지가 자주 쓰입니다.

EPEL — Extra Packages for Enterprise Linux #

Fedora 커뮤니티가 RHEL 호환으로 빌드해 두는 추가 패키지 모음. RHEL 자체에 없는 도구 (예: htop, ncdu, bat, tmux 일부 모듈) 들이 여기 있습니다.

EPEL 활성화
$ sudo dnf install -y epel-release
$ sudo dnf repolist
repo id                          repo name
epel                             Extra Packages for Enterprise Linux 9
epel-cisco-openh264              ...
rhel-9-for-aarch64-appstream-rpms ...
rhel-9-for-aarch64-baseos-rpms    ...

이제 EPEL 패키지를 깔 수 있습니다.

EPEL 패키지 설치
$ sudo dnf install htop ncdu

AlmaLinux / Rocky 사용자epel-release를 깔 때 dnf가 약간 다를 수 있습니다. 보통은 sudo dnf config-manager --set-enabled crb로 CodeReady Linux Builder (CRB) 저장소를 먼저 켜야 EPEL의 일부 패키지가 의존성을 만족합니다. RHEL 에도 CRB가 있습니다 (subscription-manager repos --enable codeready-builder-for-rhel-9-aarch64-rpms).

COPR — 개인 프로젝트용 #

Fedora의 COPR은 사용자가 만든 임시 저장소들을 모아둔 곳. 정식 EPEL에 들어가기 전 단계의 도구나, 한 사람이 메인테이너인 패키지를 받을 때.

COPR 사용
$ sudo dnf copr enable some-user/some-project
$ sudo dnf install some-package

운영에는 권장하지 않습니다. 메인테이너가 사라지면 보안 패치가 끊겨요. 학습/실험용으로만.

외부 저장소를 붙일 때 신경 쓸 것 #

항목
신뢰할 수 있는 저장소만rpm은 root로 깔립니다. 악의적 패키지면 끝
GPG 서명 검증gpgcheck=1이 켜져 있어야 함 (기본값)
우선순위 (priority)외부 저장소가 RHEL 핵심 패키지를 덮어써 버리면 곤란
활성화는 필요할 때만enabled=0으로 두고 --enablerepo로 그때만 켜기

운영 머신에서는 EPEL 정도만 켜두고, 나머지는 가능한 한 RHEL 공식 저장소 안에서 해결하는 게 안전한 길.

subscription-manager로 저장소 켜고 끄기 #

RHEL (AlmaLinux/Rocky가 아니라) 머신에서는 BaseOS / AppStream 외에도 추가 저장소가 있습니다. subscription에 따라.

활성/비활성 가능한 저장소
$ sudo subscription-manager repos --list | head -30
+----------------------------------------------------------+
    Available Repositories in /etc/yum.repos.d/redhat.repo
+----------------------------------------------------------+
Repo ID:   rhel-9-for-aarch64-supplementary-rpms
Repo Name: Red Hat Enterprise Linux 9 for ARM 64 - Supplementary (RPMs)
Repo URL:  ...
Enabled:   0

Repo ID:   codeready-builder-for-rhel-9-aarch64-rpms
Repo Name: Red Hat CodeReady Linux Builder for RHEL 9 ARM 64 (RPMs)
...
Enabled:   0

특정 저장소 켜기:

CRB 켜기
$ sudo subscription-manager repos \
    --enable codeready-builder-for-rhel-9-aarch64-rpms

$ sudo dnf repolist | grep code
codeready-builder-for-rhel-9-aarch64-rpms ...

EPEL의 일부 패키지가 CRB 의존성을 요구하기 때문에 EPEL을 켤 때 같이 켜는 일이 흔합니다.

자주 쓰는 명령 한 표 #

이번 글에서 두루 쓴 명령을 한 표에 모읍니다. 외울 필요는 없고, 막히면 돌아오세요.

명령하는 일
dnf install <pkg>패키지 + 의존성 설치
dnf remove <pkg>패키지 + 안 쓰는 의존성 제거
dnf update [<pkg>]전체 또는 특정 패키지 업데이트
dnf check-update업데이트 가능 여부만 보기
dnf search <query>이름,요약에서 검색
dnf info <pkg>패키지 상세 정보
dnf list installed/available/updates목록
dnf repoquery -l <pkg>패키지가 설치한 파일 목록
dnf repoquery --whatrequires <pkg>이 패키지를 의존하는 것들
dnf history / history info N / history undo N트랜잭션 이력과 롤백
dnf module list <pkg>모듈 stream 목록
dnf module enable <pkg>:<stream>모듈 stream 활성화
dnf module install <pkg>:<stream>/<profile>모듈 설치
dnf repolist [--all]저장소 목록
dnf config-manager --set-enabled <repo>저장소 켜기
subscription-manager repos --enable <repo>RHEL 저장소 켜기

자주 만나는 함정 #

“패키지를 찾지 못합니다” #

검색이 안 되면 보통 둘 중 하나입니다.

  1. 저장소가 비활성화dnf repolist로 확인. AppStream이 꺼져 있으면 응용 패키지가 안 보입니다.
  2. EPEL 등 외부 저장소가 필요htop, ncdu 같은 친구들은 RHEL 공식엔 없습니다.

“캐시가 이상합니다” #

오래된 메타데이터로 dnf가 헷갈릴 때:

캐시 비우기
$ sudo dnf clean all
$ sudo dnf makecache

“modules가 충돌합니다” #

dnf install postgresql-server를 쳤는데 “module이 비활성화돼 있어 설치할 수 없다” 류 에러가 나오면, 해당 모듈을 활성화하지 않은 것입니다. dnf module list postgresql로 stream 확인 후 dnf module enable postgresql:16.

가끔 두 모듈이 같은 패키지를 두고 충돌하면 dnf module reset <패키지>로 초기화하고 다시 활성화.

“EPEL을 깔았는데 의존성이 안 풀려요” #

거의 99%는 **CRB (CodeReady Linux Builder)**가 안 켜진 경우입니다. 위에서 다룬 subscription-manager repos --enable codeready-builder-... 또는 AlmaLinux/Rocky라면 dnf config-manager --set-enabled crb.

정리 #

이번 글에서 잡은 그림:

  • rpm (단일 파일) / yum (옛 이름) / dnf (현재 표준) — RHEL 9 에서는 dnf로 통일
  • 일상은 install / remove / update / search / info / list 만으로 거의 다 됨
  • dnf historyhistory undo가 RHEL 다운 기능 — 트랜잭션 단위 롤백 가능
  • BaseOS는 OS 코어 (10 년 안정), AppStream은 응용 (여러 버전)
  • modules로 PostgreSQL 13/15/16 같은 패키지의 여러 메이저 버전을 골라 깔 수 있다
  • EPEL은 Fedora가 만든 RHEL 호환 추가 저장소 — htop, ncdu 같은 도구의 출처. CRB와 함께 켜는 일이 잦음
  • 외부 저장소는 신뢰할 수 있는 곳만 / GPG 검증 켜고 / 운영엔 EPEL 정도만

다음 — systemd #

이제 패키지를 깔 줄 압니다. 다음으로 다룰 건 깐 것을 어떻게 띄우고 멈추고 부팅 시 자동으로 올라오게 하느냐 — 그게 systemd가 하는 일입니다.

#4 systemd 입문 — 서비스, target, journalctl에서는 systemd가 PID 1로 어떻게 시스템 전체를 잡고 있는지, systemctl start/stop/enable/status의 명령군, target(multi-user / graphical / rescue)의 의미, 첫 .service 유닛 파일을 직접 작성해 띄워보기, 그리고 journalctl로 모든 서비스 로그를 한곳에서 보는 흐름까지 잡습니다.

X