PEP 571 – manylinux2010 플랫폼 태그
- Author:
- Mark Williams <mrw at enotuniq.org>, Geoffrey Thomas <geofft at ldpreload.com>, Thomas Kluyver <thomas at kluyver.me.uk>
- BDFL-Delegate:
- Alyssa Coghlan <ncoghlan at gmail.com>
- Discussions-To:
- Distutils-SIG list
- Status:
- Superseded
- Type:
- Informational
- Topic:
- Packaging
- Created:
- 05-Feb-2018
- Post-History:
- Superseded-By:
- 600
- Resolution:
- Distutils-SIG message
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
초록
이 PEP는 PEP 513에서 도입된 manylinux1 태그를 계승할 manylinux2010 플랫폼 태그를 만들 것을 제안합니다. 또한 호환되는 플랫폼에서 manylinux2010 배포물을 업로드, 다운로드, 설치할 수 있도록 PyPI와 pip을 모두 업데이트할 것을 제안합니다.
근거
이름 그대로 manylinux1 플랫폼 태그는 많은 리눅스 시스템에서 바이너리 확장 모듈 설치를 현실로 만들었습니다. cryptography [2]나 numpy [3] 같은 라이브러리는 이제 일반적인 아키텍처에서의 설치가 불안정한 개발 환경과 빌드 툴체인에 의존하지 않게 되어 Python 개발자가 더 쉽게 사용할 수 있게 되었습니다.
manylinux1 휠은 포함된 확장 모듈이 소수의 시스템 수준 공유 라이브러리에만 링크하도록 허용하여 이식성을 달성합니다. 이 라이브러리들은 하위 호환성 정책의 혜택을 받을 만큼 오래된 버전 지정 심볼을 내보냅니다. 예를 들어 glibc에 의존하는 manylinux1 휠의 확장 모듈은 버전 2.5 이하를 대상으로 빌드되어야 합니다. 그러면 필요한 심볼을 여전히 버전 2.5로 내보내는 더 최신 glibc 버전을 제공하는 시스템에서 실행할 수 있습니다.
PEP 513은 화이트리스트에 포함된 공유 라이브러리와 그 심볼 버전을 CentOS 5.11에서 가져왔는데, 이는 해당 PEP 작성 당시 지원되던 가장 오래된 CentOS 릴리스였습니다. 안타깝게도 CentOS 5.11은 2017년 3월 31일에 지원이 종료되었으며, 계속 사용하지 말라는 명확한 경고가 함께 발표되었습니다. [4] 보안 패치 같은 추가 업데이트는 더 이상 제공되지 않습니다. 이는 해당 패키지가 오래된 버전에 머무르게 되어 manylinux1 Docker 이미지를 사용하는 Python 소프트웨어 패키저의 노력을 방해한다는 것을 의미합니다.
이제 CentOS 6이 지원되는 가장 오래된 CentOS 릴리스이며, 2020년 11월 30일까지 유지 보수 업데이트를 받습니다. [5] 우리는 CentOS 6에서 파생된 manylinux2010이라는 새로운 PEP 425 방식의 플랫폼 태그를 만들고, manylinux 툴체인, PyPI, pip이 이를 지원하도록 업데이트할 것을 제안합니다.
이것은 원래 manylinux2로 제안되었지만, 버전 관리 방식이 연도(CalVer [22]라고도 합니다)를 사용하도록 변경되었습니다. 이렇게 하면 향후 manylinux 태그를 순서와 상관없이 정의하기가 더 쉬워집니다. 예를 들어 가상의 manylinux2017 표준이 manylinux2014보다 먼저 새로운 PEP를 통해 정의될 수도 있고, 이 PEP의 대상보다 오래되었지만 manylinux1보다는 새로운 시스템을 대상으로 하는 manylinux2007 표준이 정의될 수도 있습니다.
연도 기반 버전 관리는 어떤 Linux 배포판 버전이 어떤 태그를 지원하는지에 대한 대략적인 정보도 줍니다. manylinux2010은 2010년 이후 릴리스된 대부분의 배포판 버전에서 동작합니다. 하지만 이는 근사치일 뿐입니다. 실제 호환성 규칙은 아래에 정의되어 있으며, 일부 최신 배포판은 이를 충족하지 못할 수도 있습니다.
manylinux2010 정책
다음 기준에 따라 linux 휠이 manylinux2010 태그를 사용할 자격이 있는지 결정됩니다:
- 휠에는 CentOS 6이 지원하는 두 아키텍처인 x86_64와 i686 중 하나를 대상으로 컴파일된 바이너리 실행 파일과 공유 객체만 포함할 수 있습니다. [5]
- 휠의 바이너리 실행 파일이나 공유 객체는 다음 화이트리스트에 있는 라이브러리를 제외한 외부 제공 라이브러리에 링크할 수 없습니다:
libgcc_s.so.1 libstdc++.so.6 libm.so.6 libdl.so.2 librt.so.1 libc.so.6 libnsl.so.1 libutil.so.1 libpthread.so.0 libresolv.so.2 libX11.so.6 libXext.so.6 libXrender.so.1 libICE.so.6 libSM.so.6 libGL.so.1 libgobject-2.0.so.0 libgthread-2.0.so.0 libglib-2.0.so.0
이 목록은
manylinux1에 대해 화이트리스트에 포함된 외부 제공 라이브러리에서libncursesw.so.5와libpanelw.so.5를 뺀 것과 동일합니다. [7]libpythonX.Y는 PEP 513에 설명된 것과 같은 이유로 여전히 포함될 수 없습니다.libcrypt.so.1은 Fedora 30이 이 라이브러리 대신libcrypt.so.2를 탑재하고 출시된 이후 소급하여 화이트리스트에서 제거되었습니다.Debian 기반 시스템에서는 다음 패키지가 이러한 라이브러리를 제공합니다:
패키지 라이브러리 libc6 libdl.so.2, libresolv.so.2, librt.so.1, libc.so.6, libpthread.so.0, libm.so.6, libutil.so.1, libnsl.so.1 libgcc1 libgcc_s.so.1 libgl1 libGL.so.1 libglib2.0-0 libgobject-2.0.so.0, libgthread-2.0.so.0, libglib-2.0.so.0 libice6 libICE.so.6 libsm6 libSM.so.6 libstdc++6 libstdc++.so.6 libx11-6 libX11.so.6 libxext6 libXext.so.6 libxrender1 libXrender.so.1 RPM 기반 시스템에서는 다음 패키지가 이 라이브러리를 제공합니다:
패키지 라이브러리 glib2 libglib-2.0.so.0, libgthread-2.0.so.0, libgobject-2.0.so.0 glibc libresolv.so.2, libutil.so.1, libnsl.so.1, librt.so.1, libpthread.so.0, libdl.so.2, libm.so.6, libc.so.6 libICE libICE.so.6 libX11 libX11.so.6 libXext: libXext.so.6 libXrender libXrender.so.1 libgcc: libgcc_s.so.1 libstdc++ libstdc++.so.6 mesa libGL.so.1 - 휠에 포함된 바이너리 실행 파일이나 공유 객체가 화이트리스트에 있는 라이브러리 중 버전이 지정된 심볼도 내보내는 라이브러리에 링크되어 있다면, 이들은 다음 최대 버전까지만 의존할 수 있습니다:
GLIBC_2.12 CXXABI_1.3.3 GLIBCXX_3.4.13 GCC_4.5.0
예를 들어,
manylinux2010휠은GLIBC_2.4버전의glibc심볼을 요구하는 바이너리 산출물을 포함할 수 있습니다. 이 버전은 최대 버전인GLIBC_2.12보다 이전 버전이기 때문입니다. - 휠이 CPython 2의 어떤 버전이나 CPython 3.0부터 3.2까지(3.2 포함)의 버전을 대상으로 빌드된 경우, 해당 휠은 유니코드 ABI를 나타내는 CPython ABI 태그를 반드시 포함해야 합니다. 따라서 Python 2를 대상으로 빌드된
manylinux2010휠은 UCS-4 ABI를 사용하는 인터프리터를 대상으로 빌드되었음을 나타내는cpy27mu태그나, UCS-2 ABI를 사용하는 인터프리터를 나타내는cpy27m태그 중 하나를 반드시 포함해야 합니다. (PEP 3149, [9]) - 휠은
PyFPE_jbuf심볼을 요구해서는 안 됩니다. 이 조건은--with-fpectlconfigure플래그 없이 컴파일된 Python을 대상으로 휠을 빌드하면 충족됩니다.
규격을 준수하는 휠의 컴파일
manylinux1과 마찬가지로, auditwheel 도구는 manylinux2010 Docker 컨테이너 안에서 pip wheel 또는 bdist_wheel로 빌드된 linux 휠에 manylinux2010 플랫폼 태그를 추가합니다.
Docker 이미지
manylinux2010 휠로 안정적으로 변환할 수 있는 바이너리 linux 휠을 빌드할 수 있도록 CentOS 6 기반의 manylinux2010 Docker 이미지 두 개가 제공됩니다. [10] x86_64 이미지와 i686 이미지에는 새 컴파일러 모음(devtoolset-8의 gcc, g++, gfortran)과 함께 최신 릴리스의 Python과 pip이 설치되어 있습니다.
vsyscall이 없는 커널과의 호환성
Docker 컨테이너는 자신의 유저랜드가 호스트의 커널과 호환된다고 가정합니다. 안타깝게도 점점 더 흔해지고 있는 커널 구성 때문에 x86_64 CentOS 6 Docker 이미지에서는 이 가정이 깨집니다.
glibc 2.14 이하 버전은 x86_64에서 커널이 vsyscall이라는 구식 시스템 호출 최적화를 제공할 것을 요구합니다. [11] 이 최적화를 위해 커널은 자주 호출되는 시스템 호출(대표적으로 time(2))이 담긴 읽기 전용 페이지를 각 프로세스의 고정된 메모리 위치에 매핑합니다. 그러면 glibc는 vsyscall 페이지 안의 적절한 오프셋을 가리키는 함수 포인터를 역참조하여 호출하는 방식으로 이 시스템 호출을 실행합니다. 이렇게 하면 일반적인 시스템 호출 실행에 따르는 커널 진입 오버헤드를 피할 수 있습니다. vsyscall은 vDSO(“virtual dynamic shared object”, 가상 동적 공유 객체)라는 동등한 메커니즘으로 대체되어 오래전부터 사용 중단(deprecated) 상태입니다. vDSO에서는 커널이 그 대신 최적화된 시스템 호출을 담은 재배치 가능한 가상 공유 객체를 각 프로세스에 매핑합니다. [12]
vsyscall 페이지는 주소 공간 배치 무작위화(ASLR)의 대상이 되지 않기 때문에 심각한 보안 문제를 일으킵니다. 위치와 내용을 예측할 수 있기 때문에 이 페이지는 반환 지향 프로그래밍(return-oriented programming) 공격에 쓰이는 가젯을 얻기 좋은 곳이 됩니다. [13] 그런데 이 페이지를 없애면 x86_64 ABI가 깨집니다. vsyscall에 의존하는 glibc 버전은 존재하지 않는 페이지를 가리키는 시스템 호출 포인터를 역참조하려다 세그멘테이션 오류를 일으키기 때문입니다. 절충안으로 Linux 3.1은 프로세스에 매핑되는 실행 가능한 코드를 줄여 ROP 가젯으로 쓰일 재료도 줄인 “에뮬레이션” vsyscall을 구현했습니다. [14] vsyscall=emulated는 여러 해 동안 대부분의 배포판 커널에서 기본 구성이었습니다.
안타깝게도 vsyscall 에뮬레이션도 여전히 예측 가능한 코드를 일정한 메모리 위치에 노출하므로 반환 지향 프로그래밍에 계속 악용될 수 있습니다. [15] 이제 대부분의 배포판이 vsyscall에 의존하지 않는 glibc 버전으로 업그레이드했기 때문에, vsyscall을 아예 지원하지 않는 커널을 배포하기 시작하고 있습니다. [16]
CentOS 5.11과 6은 모두 vsyscall 페이지에 의존하는 glibc 버전(각각 2.5와 2.12.2)을 포함하고 있으므로, 둘 중 어느 것을 기반으로 한 컨테이너든 여러 배포판의 향후 릴리스에서 제공되는 커널에서는 실행할 수 없습니다. [17] 예를 들어 Travis CI가 vsyscall 인터페이스를 제공하지 않는 커널에서 작업을 실행하기 시작하면, Python 패키지 작성자들은 그곳에서 우리 Docker 이미지를 사용해 manylinux 휠을 빌드할 수 없게 됩니다. [18]
우리는 glibc git 저장소에서 vsyscall에 대한 모든 의존성을 제거한 변경 사항을 manylinux2010 이미지에 포함된 glibc 버전으로 백포트하는 패치를 만들었습니다. [19] glibc를 다시 빌드하는 데에는, 따라서 manylinux2010 이미지 자체를 빌드하는 데에는 여전히 vsyscall 메커니즘을 제공하는 호스트 커널이 필요합니다. 하지만 그렇게 만들어진 이미지는 이 메커니즘을 제공하는 호스트와 제공하지 않는 호스트 양쪽에서 모두 실행할 수 있습니다. vsyscall 인터페이스는 실행 중인 프로세스에만 적용되는 최적화이므로, 이 수정된 이미지로 빌드한 manylinux2010 휠은 수정하지 않은 CentOS 6 시스템에서 빌드한 휠과 동일할 것입니다. 또한 vsyscall 문제는 x86_64에만 해당하며, i686 ABI에는 포함되지 않습니다.
Auditwheel
auditwheel 도구도 manylinux2010 휠을 만들 수 있도록 업데이트되었습니다. [20] 그 밖의 동작과 목적은 PEP 513과 달라진 점이 없습니다.
설치 프로그램을 위한 플랫폼 감지
플랫폼은 PEP 513에서 설명한 _manylinux 모듈에 manylinux2010_compatible 불리언 속성을 정의할 수 있습니다. 이 속성이 False이면 해당 플랫폼은 manylinux2010과 호환되지 않는 것으로 간주됩니다.
_manylinux 모듈을 찾을 수 없거나 이 모듈에 manylinux2010_compatible 속성이 없으면, 도구는 대신 glibc를 확인하는 방식으로 대체할 수 있습니다. 플랫폼에 glibc 2.12 이상이 있으면, _manylinux 모듈이 달리 알리지 않는 한 호환되는 것으로 간주합니다.
구체적으로, 제안하는 알고리즘은 다음과 같습니다:
def is_manylinux2010_compatible():
# Only Linux, and only x86-64 / i686
from distutils.util import get_platform
if get_platform() not in ["linux-x86_64", "linux-i686"]:
return False
# Check for presence of _manylinux module
try:
import _manylinux
return bool(_manylinux.manylinux2010_compatible)
except (ImportError, AttributeError):
# Fall through to heuristic check below
pass
# Check glibc version. CentOS 6 uses glibc 2.12.
# PEP 513 contains an implementation of this function.
return have_compatible_glibc(2, 12)
manylinux1 휠과의 하위 호환성
PEP 513에서 설명했듯이, manylinux1 화이트리스트 라이브러리에 대해 지정된 심볼 버전은 상한을 이룹니다. 이 PEP에서 manylinux2010에 대해 정의한 심볼 버전도 마찬가지입니다. 그 결과, manylinux1 휠은 manylinux2010 휠로 간주됩니다. 따라서 manylinux2010 플랫폼 태그를 인식하는 pip은 manylinux2010 휠을 사용할 수 없을 때 manylinux2010 플랫폼에 manylinux1 휠을 설치하며, 이는 플랫폼을 명시적으로 설정한 경우에도 마찬가지입니다. [21]
PyPI 지원
PyPI는 manylinux1을 허용하는 것과 같은 방식으로 manylinux2010 플랫폼 태그가 포함된 휠의 업로드를 허용해야 합니다. PyPI는 manylinux2010 휠의 호환성을 검증하려고 해서는 안 됩니다.
PEP 571 변경 사항 요약
이 PEP가 승인된 후 받은 피드백을 바탕으로 이 PEP에 다음과 같은 변경이 이루어졌습니다:
- 32비트 CentOS 6에 대응하기 위해
libgcc_s의 최대 버전 심볼을GCC_4.3.0에서GCC_4.5.0으로 갱신했습니다. x86_64용libgcc_s에는GCC_4.3.0부터GCC_4.5.0까지 추가된 심볼이 없으므로, 이 변경은 x86_64에 영향을 주지 않습니다.
참고 문헌
Copyright
This document has been placed into the public domain.