RPM 또는 DNF 패키지 설치 자동화 스크립트가 낮은 확률로 lock 에러로 실패할 수 있습니다. 재실행하면 성공해서 넘어가기만 시간이 지나면 어느날 또 lock 에러가 발생할 수 있습니다.
왜 rpm/dnf는 lock을 쓸까요. 이 글은 그 원리에서 시작해 lock 확인 방법 그리고 Ansible에서 안전하게 기다리는 방법을 정리했습니다.
RPM 또는 dnf의 lock
rpm/dnf는 한 번에 한 작업만 실행되도록 lock을 사용하는데, 설치 스크립트가 병렬로 설치하거나 cron 업데이트와 겹치면, 뒤늦게 실행된 쪽은 lock을 얻지 못하고 실패합니다.

RPM/DNF는 왜 lock을 쓰는가
RPM은 database를 파일 lock으로 지킵니다. RPM database는 /var/lib/rpm에 있고, RPM은 /var/lib/rpm/.rpm.lock 파일에 fcntl write lock을 겁니다. 설치 트랜잭션(rpmtsRun)과 database 초기화·재빌드가 이 lock으로 직렬화됩니다. 익숙한 에러 warning: waiting for transaction lock on /var/lib/rpm/.rpm.lock가 바로 이 lock을 기다리는 상황입니다.
왜 database 엔진 내부 lock이 아니라 파일 lock일까요. 패키지 설치는 database 레코드만 바꾸는 게 아니라 파일 시스템에 실제 파일을 풀고 지우는 작업까지 포함합니다. database 트랜잭션 lock은 database 변경은 보호하지만 파일 시스템 변화까지 한 단위로 묶어주지는 못합니다. 설치 전체를 하나로 직렬화하려면 파일 lock이 필요합니다.
ls /var/lib/rpm

lock file
lock file은 파일을 lock처럼 사용하는 개념입니다. /tmp 경로에 lock 파일을 만들고, 명령어를 실행할 때마다 lock이 안 걸려 있는지 확인한 뒤 실행하는 식입니다.
리눅스에서는 flock 명령어로 이 lock file을 직접 실습할 수 있습니다. flock은 지정한 파일에 lock을 걸고, 그 lock을 잡은 채로 뒤에 오는 명령어를 실행합니다.
# lock 파일 생성
touch /tmp/akbun.lock
# sleep 명령어를 실행하기 전에 lock 획득
flock /tmp/akbun.lock sleep 60
누군가 이미 lock을 걸었다면 lock 획득에 실패하고, 뒤의 명령어는 실행되지 않습니다. -n은 lock을 기다리지 않고 바로 실패하라는 옵션입니다.
flock -n /tmp/akbun.lock echo "lock acquired" || echo "lock busy"

lock이 걸렸는지 확인하기
lock이 걸려 있는지 확인하는 방법은 여러가지가 있고 4가지를 소개합니다.
첫째, fuser로 lock 파일을 누가 잡고 있는지 봅니다. lock이 안 걸려 있으면 결과가 비어 있고, 걸려 있으면 파일을 잡고 있는 프로세스가 나옵니다.


둘째, DNF가 남기는 pid 파일을 확인합니다. DNF는 lock을 설정한 process id를 metadata·rpmdb·download 작업별로 파일에 기록합니다.
/var/cache/dnf/metadata_lock.pid
/var/lib/dnf/rpmdb_lock.pid
/var/cache/dnf/download_lock.pid
DNF의 lock은 실제 파일 lock이 아니라 이 pid 파일의 존재와 안에 적힌 프로세스가 살아 있는지를 확인하는 방식입니다. 그래서 프로세스가 비정상 종료하면 lock 파일이 남아 오작동할 수 있습니다.
셋째, 로그를 확인합니다. DNF는 /var/log/dnf.log에 로그를 남깁니다. RPM은 별도 로그 파일이 없어서, database에 기록된 패키지 설치·변경 시간을 보고 lock을 추측해야 합니다.
# dnf
grep -iE 'lock|waiting for process|pid' /var/log/dnf.log
# rpm
rpm -qa --last
넷째, 패키지 매니저 프로세스가 실행 중인지 봅니다. 스크립트가 실행 즉시 lock으로 실패했다면 process 목록에서 dnf, rpm을 찾습니다.
pgrep -x 'dnf|dnf5|yum|packagekitd|rpm'
ansible playbook에서 lock 대기
dnf 모듈을 쓴다면 lock_timeout으로 lock을 기다립니다. lock이 풀릴 때까지 최대 지정한 초만큼 대기합니다.
- name: install packages
ansible.builtin.dnf:
name:
- nginx
- redis
state: present
lock_timeout: 60
dnf 모듈이 아니라 rpm 등을 직접 쓴다면 프로세스 실행 여부로 대기합니다. pgrep이 프로세스를 못 찾아 종료 코드가 0이 아닐 때(=패키지 매니저가 idle) 다음 단계로 넘어갑니다.
- name: wait until pkg manager is idle
ansible.builtin.shell: pgrep -x 'dnf|dnf5|yum|packagekitd|rpm'
register: pkg_busy
until: pkg_busy.rc != 0
retries: 36
delay: 5
changed_when: false
failed_when: false
마치며, rpm 또는 dnf 자동화는 lock이 걸릴 수 있다는 것을 생각해야 한다.
rpm, dnf는 패키지가 꼬이지 않도록 한 번에 하나씩만 실행되게 lock을 씁니다. 손으로 명령어를 칠 때는 이 lock이 잘 보이지 않지만, 스크립트로 자동화하면 병렬 실행이나 cron 업데이트와 겹치는 순간 lock 충돌이 드러납니다. 그래서 자동화 스크립트를 짤 때는 lock을 대기하거나 패키지 작업이 겹치지 않게 하는 로직을 구현해야 합니다.
참고자료
'전공영역 공부 기록' 카테고리의 다른 글
| LiteLLM QuickStart - Budget limit(비용제한) (0) | 2026.07.12 |
|---|---|
| LiteLLM QuickStart - 모델 등록하고 호출해보기 (0) | 2026.07.12 |
| 같은 코드를 여러 팀이 관리할 때 테스트 환경은 어떻게 제공해야할까?(feat Argo CD Pull Request generator) (0) | 2026.07.04 |
| ArgoCD private repo 연동: Github App이 PAT보다 안전한 이유 (0) | 2026.06.29 |
| AWS CodeBuild에서 Github 토큰도 없이 어떻게 private repository를 clone할까? (0) | 2026.06.23 |