LabHub
배우기 러닝패스 코스

Package Management

Why Package Managers Came About

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

한 줄 요약

패키지 관리자는 파일을 푸는 도구가 아니라 "무엇이 무엇을 필요로 하는가"라는 그래프를 푸는 도구다.

Concept map: "무엇이 무엇을 필요로 하는가"라는 그래프를 푸는 도구 · 메타데이터 · 그래프 문제 · 첫째, 의존성의 단위가 패키지 이름이 아닐 수 있다.

왜 이게 필요했나

소프트웨어를 tarball 로 배포하던 시절의 설치는 이랬다. 압축을 풀고, ./configure 를 돌리고, 없다는 라이브러리를 하나씩 찾아 설치하고, 그 라이브러리가 또 다른 것을 요구하면 다시 찾아 나선다. 이걸 "의존성 지옥" 이라고 불렀다.

문제의 본질은 파일을 옮기는 일이 어려운 게 아니라, 무엇을 먼저 옮겨야 하는지 아무도 모른다는 것이었다. 그래서 패키지 형식은 파일 묶음에 메타데이터를 붙였다. 이 패키지는 무엇을 제공하는가(Provides), 무엇을 요구하는가(Depends), 무엇과 충돌하는가(Conflicts). 이제 설치는 파일 복사 문제가 아니라 그래프 문제가 됐고, 그래프 문제는 컴퓨터가 사람보다 잘 푼다.

어떻게 동작하나

deb 와 rpm 의 세부는 다르지만 뼈대는 같다.

개념 무엇인가 데비안 표기 RPM 표기
이름·버전 패키지를 식별 Package, Version Name, Version, Release
필수 의존 없으면 못 씀 Depends Requires
약한 의존 있으면 좋음 Recommends, Suggests Recommends, Suggests
제공 가상 이름을 만족 Provides Provides
충돌 같이 못 있음 Conflicts, Breaks Conflicts
아키텍처 어느 CPU 용인가 amd64 / all x86_64 / noarch

여기서 가장 자주 발목을 잡는 것이 세 가지다.

첫째, 의존성의 단위가 패키지 이름이 아닐 수 있다. RPM 쪽이 특히 그렇다. Requires: libnl-3.so.200()(64bit) 처럼 공유 라이브러리의 소네임이 그대로 의존 대상이 된다. 그래서 "패키지 하나만 받아 오면 되지 않느냐"는 요청이 폐쇄망에서 반나절짜리 작업이 된다.

둘째, 가상 패키지(Provides)가 있다. mail-transport-agent 를 요구하면 postfix 도 exim4 도 그 요구를 만족시킨다. 그래서 "이 이름의 패키지가 저장소에 없는데 왜 설치가 되지?" 같은 상황이 생긴다.

셋째, 버전 비교 규칙이 직관과 다르다. 데비안은 1.0~rc11.0 보다 작다(틸데는 어떤 문자보다도 작다). RPM 은 epoch 가 있어서 1:1.02.0 보다 크다. 그리고 epoch 는 파일 이름에 나타나지 않는다. 조용하고 치명적인 차이다.

현장에서 만나는 모습

폐쇄망 반입 요청이 "rpm 파일 하나만 받아다 주세요" 로 들어오는 일이 잦다. 받아서 넣으면 nothing provides libnl-3.so.200()(64bit) needed by htop 같은 에러가 난다. 다시 나가서 그걸 받아 오면 또 다른 게 없다고 한다. USB 를 서너 번 왕복하면 반나절이 지나 있고, 반입 심의는 하루에 한 번뿐이다.

그래서 숙련자는 처음부터 그래프를 통째로 푼 결과를 들고 간다. 그 계산을 어디서 하느냐가 이 코스 후반부의 주제다.

패키지 관리자가 하지 않는 일

패키지 관리자는 파일을 놓고 의존성을 풀지만, 그 뒤의 일은 대부분 하지 않는다. 이 경계를 모르면 "설치했는데 왜 안 되지" 가 반복된다.

설정 파일은 덮어쓰지 않는다. 패키지 갱신 시 우리가 고친 설정 파일이 있으면, 관리자는 덮어쓰는 대신 물어보거나 새 파일을 옆에 .dpkg-dist·.rpmnew 같은 이름으로 놓아둔다. 그래서 갱신 뒤에 이런 파일이 쌓여 있는지 확인하는 절차가 필요하다. 새 버전이 요구하는 설정 항목이 있어도 우리 파일에는 없기 때문에, 조용히 기본값으로 동작하다가 나중에 문제가 된다.

서비스를 재시작해 줄지는 배포판마다 다르다. 어떤 배포판은 갱신 후 자동으로 재시작하고, 어떤 배포판은 하지 않는다. 자동으로 하는 쪽은 예기치 않은 순간에 서비스가 끊길 수 있고, 하지 않는 쪽은 옛 코드가 계속 도는 채로 남는다. 어느 쪽인지 알고 그에 맞는 절차를 두는 것이지, 기본 동작을 믿고 넘어갈 일이 아니다.

설치하지 않은 것은 지워 주지 않는다. 패키지를 지워도 그것이 만들어 낸 로그, 데이터 디렉터리, 사용자 계정은 대개 남는다. 데비안 계열에서 removepurge 가 나뉘어 있는 것이 이 차이다. 남는 것이 있다는 사실 자체는 안전장치이지만, 지웠다고 믿고 있으면 나중에 같은 패키지를 다시 깔았을 때 옛 설정이 되살아나 혼란을 일으킨다.

언어별 패키지 관리자와는 서로를 모른다. 시스템 패키지로 깐 파이썬 라이브러리와 pip 로 깐 것이 섞이면 어느 쪽이 쓰이는지 예측하기 어려워지고, 시스템 갱신이 애플리케이션을 깨뜨린다. 그래서 애플리케이션 의존성은 가상 환경이나 컨테이너로 분리하고, 시스템 패키지 관리자는 시스템의 것만 다루게 두는 것이 원칙이다.

다음에서 할 것

apt 의 실전 조작으로 넘어간다. 검색·설치·제거는 시작일 뿐이고, hold 와 pin 으로 버전을 붙잡는 법까지 손에 익힌다.