대상 OS: Rocky Linux 9

업데이트는 대부분 ‘잘’ 되는데, 문제는 가끔 생기는 그 1번이 운영 시간을 다 먹어버린다는 점입니다.
패키지 업데이트가 꼬였을 때 사람들은 대개 “그냥 재설치”를 떠올리지만, 서버에서는 그게 제일 비싼 선택입니다.
Rocky Linux 9의 dnf는 기록과 롤백(정확히는 되돌림에 가까운 작업)을 꽤 잘 지원합니다.
핵심은 “무슨 패키지가, 어떤 트랜잭션으로, 어떤 리포지토리에서 왔는지”를 먼저 확정하는 겁니다.
오늘 글은 업데이트 사고를 빠르게 복구하고, 같은 사고를 덜 겪도록 만드는 실전 루틴입니다.

먼저 상황을 고정: 지금 시스템 상태를 ‘한 장’으로 스냅샷

문제 해결 시작 전에, 나중에 비교할 기준선을 남겨두면 훨씬 편합니다.

1) OS/커널/업타임 확인

cat /etc/os-release
uname -r
uptime

2) 최근 dnf 작업 이력과 마지막 트랜잭션

dnf -y history

3) 지금 설치된 패키지 버전 확인(문제가 된 패키지 후보)

rpm -qa --last | head -n 30

`rpm -qa --last`는 “최근 바뀐 것”을 직관적으로 보여줘서, 장애 발생 시점과 맞추기 좋습니다.

dnf history 읽는 법: “언제/무엇을/왜”를 확정하기

1) 트랜잭션 목록

dnf history

2) 특정 트랜잭션 상세 보기

dnf history info 17

여기서 꼭 봐야 하는 포인트:
- 어떤 패키지가 설치/업데이트/삭제됐는지
- 작업이 어느 리포지토리에서 왔는지
- 커맨드 라인(누가 어떤 옵션으로 실행했는지)

3) 실패한 트랜잭션이 있는지 확인

dnf history | head -n 30

표시가 `*` 등으로 비정상으로 남아 있는 경우가 있어서, 실패 흔적을 찾는 용도로 좋습니다.

“바로 전 상태로” 되돌리고 싶을 때: history undo / rollback 감각

DNF의 되돌리기는 만능이 아닙니다.
하지만 “업데이트 직후 서비스가 깨졌다” 같은 케이스에서는 가장 빠른 1차 대응이 됩니다.

1) 특정 트랜잭션 되돌리기(undo)

sudo dnf -y history undo 17

2) 특정 시점까지 되돌리기(rollback)

sudo dnf -y history rollback 15

운영 팁:
- rollback은 그 이후의 여러 트랜잭션을 한 번에 되감으니, 변경폭이 커질 수 있습니다.
- undo는 한 트랜잭션만 되돌리니 더 안전한 편입니다.

주의:
- 중간에 repo 구성이 바뀌었거나, 이미 repo에서 사라진 버전이 있으면 완벽히 재현되지 않을 수 있습니다.

특정 패키지만 “예전 버전으로” 내리기: dnf downgrade

서비스가 깨지는 경우는 보통 핵심 패키지 몇 개가 원인일 때가 많습니다.
그럴 땐 트랜잭션 전체를 되감는 것보다 ‘해당 패키지만’ 내려서 범위를 최소화할 수 있습니다.

1) 현재 버전 확인

rpm -q nginx

2) 다운그레이드 시도

sudo dnf -y downgrade nginx

3) 가능한 버전 후보를 보고 선택하고 싶을 때

dnf --showduplicates list nginx

4) 특정 버전을 지정해서 설치(사실상 내려가기)

sudo dnf -y install nginx-1:1.20.1-14.el9

패키지 이름에 epoch가 포함될 수 있어서(예: `1:`), `--showduplicates`로 확인한 표기를 그대로 쓰는 게 안전합니다.

“또 자동으로 올라가서 깨지는 것” 방지: versionlock

한 번 다운그레이드로 살려놨는데 다음 업데이트 창구에서 다시 올라가 버리면, 같은 장애가 반복됩니다.
그럴 땐 잠깐 버전을 고정해두고, 상위 호환이 확인된 뒤 풀어주는 방식이 실무적으로 안전합니다.

1) 플러그인 설치

sudo dnf -y install python3-dnf-plugin-versionlock

2) 현재 설치 버전을 잠금

sudo dnf versionlock add nginx

3) 잠금 목록 확인

dnf versionlock list

4) 잠금 해제

sudo dnf versionlock delete nginx

운영 감각:
- 영구 고정이 아니라 “임시로 묶어두는 안전핀”으로 쓰는 게 좋습니다.
- 고정한 패키지가 의존성 때문에 업데이트 전체를 막는 경우가 있으니, 다음 섹션의 트러블슈팅 루틴이 같이 필요합니다.

업데이트가 꼬이는 흔한 이유 4가지와 확인 커맨드

# 1) 리포지토리 충돌(같은 패키지를 여러 repo가 제공)

1) 패키지 출처 확인

dnf -C info nginx

2) 어떤 repo가 후보를 제공하는지 보기

dnf repoquery --info nginx | head -n 50

(repoquery가 없다면 dnf-plugins-core를 설치하세요.)

sudo dnf -y install dnf-plugins-core

# 2) 메타데이터 캐시가 꼬임

가끔은 캐시를 비우는 것만으로도 해결됩니다.

1) 캐시 정리 후 다시 시도

sudo dnf clean all
sudo dnf makecache

# 3) “의존성 해결 불가”로 업데이트가 멈춤

1) 어떤 패키지가 막는지 단서 얻기

sudo dnf -y update --best --allowerasing

- `--best`는 가능한 최신 조합을 강제해서 문제를 더 빨리 드러내고,
- `--allowerasing`은 충돌 패키지를 지우는 선택지를 열어줍니다.

운영에서는 `--allowerasing`이 꽤 강력한 만큼, 제거될 패키지 목록을 반드시 눈으로 확인한 다음 진행하는 게 좋습니다.

# 4) “모듈 스트림” 때문에 원하는 버전이 안 뜸(특히 언어 런타임/DB/웹스택)

Rocky 9는 모듈 스트림 개념이 있어서, 모듈이 특정 스트림으로 고정되어 있으면 후보가 제한될 수 있습니다.

1) 모듈 목록과 활성 스트림 확인

dnf module list

2) 특정 모듈 상태 확인

dnf module list php

이 글은 DB 주제를 피하는 조건이 있으니 DB 예시는 생략하지만, 원리는 동일합니다.

“서비스는 살렸는데 찜찜하다”를 줄이는 점검 루틴

업데이트를 되돌리거나 다운그레이드했으면, 아래를 꼭 확인하세요.

1) 깨진 패키지 의존성/DB(패키지 DB) 점검

sudo rpm -Va | head

`rpm -Va`는 출력이 많을 수 있으니, 바로 전체를 해결하려 들기보다 “이상 징후가 있는지”만 먼저 보는 용도로 씁니다.

2) 문제 서비스의 실제 바이너리/설정이 예상 버전인지 확인

rpm -q nginx
nginx -v 2>&1 || true

3) 시스템 로그에서 업데이트 직후 에러만 쭉 훑기

journalctl --since '-2 h' -p err --no-pager

마지막으로: 업데이트를 ‘작게’ 만들면 장애도 작아진다

dnf가 제공하는 기능 중 운영에 특히 도움이 되는 습관은 이 두 가지입니다.

1) 한 번에 다 올리지 말고 “영향 큰 묶음”을 나눠서 올리기

2) history를 남기는 방식(누가, 어떤 창구에, 어떤 명령으로)을 정해두기

업데이트는 피할 수 없고, 사고도 0으로 만들기 어렵습니다.
하지만 사고가 났을 때 “어제 나 자신이 남긴 기록”이 곧 복구 속도라는 건, 거의 예외가 없습니다.