Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

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

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

초록

이 PEP는 PEP 513에서 도입된 manylinux1 태그를 계승할 manylinux2010 플랫폼 태그를 만들 것을 제안합니다. 또한 호환 가능한 플랫폼에서 manylinux2010 배포 패키지를 업로드하고 다운로드하며 설치할 수 있도록 PyPI와 pip를 모두 업데이트할 것을 제안합니다.

근거

이름 그대로 manylinux1 플랫폼 태그는 많은 Linux 시스템에서 바이너리 확장 모듈을 설치할 수 있게 했습니다. 이제 일반적인 아키텍처에서의 설치가 취약한 개발 환경과 빌드 도구 체인에 의존하지 않으므로, cryptography [2]numpy [3]같은 라이브러리를 Python 개발자가 더 쉽게 사용할 수 있습니다.

manylinux1 휠은 포함된 확장 모듈이 버전이 지정된 심볼을 내보내며 하위 호환성 정책의 혜택을 받을 수 있을 만큼 오래된 소수의 시스템 수준 공유 라이브러리에만 링크하도록 허용함으로써 이식성을 확보합니다. 예를 들어 glibc에 의존하는 manylinux1 휠의 확장 모듈은 버전 2.5 이하에 대해 빌드해야 하며, 이후 필요한 심볼을 버전 2.5로 여전히 내보내는 최신 glibc 버전을 제공하는 시스템에서 실행할 수 있습니다.

PEP 513은 작성 당시 지원되는 CentOS 릴리스 중 가장 오래된 CentOS 5.11에서 허용 목록에 포함할 공유 라이브러리와 해당 심볼 버전을 가져왔습니다. 안타깝게도 CentOS 5.11은 지속적인 사용에 대한 명확한 경고와 함께 2017년 3월 31일에 지원 종료에 도달했습니다. [4] 보안 패치와 같은 추가 업데이트는 더 이상 제공되지 않습니다. 이는 해당 패키지가 오래된 버전으로 남아 manylinux1 Docker 이미지를 사용하는 Python 소프트웨어 패키저의 작업을 방해한다는 의미입니다.

이제 CentOS 6이 지원되는 가장 오래된 CentOS 릴리스이며, 2020년 11월 30일까지 유지 관리 업데이트를 받습니다. [5] CentOS 6에서 새로운 PEP 425 스타일의 manylinux2010이라는 플랫폼 태그를 파생하고, 이를 지원하도록 manylinux 도구 체인과 PyPI 및 pip를 업데이트할 것을 제안합니다.

이는 원래 manylinux2로 제안되었지만, 버전 관리 방식이 달력 연도(일명 CalVer [22])를 사용하도록 변경되었습니다. 이를 통해 향후 manylinux 태그를 순서와 관계없이 더 쉽게 정의할 수 있습니다. 예를 들어 가상의 manylinux2017 표준을 manylinux2014보다 먼저 새로운 PEP를 통해 정의하거나, 이 PEP의 대상 시스템보다 오래되었지만 manylinux1보다 새로운 시스템을 대상으로 하는 manylinux2007 표준을 정의할 수 있습니다.

달력 기반 버전 관리는 어떤 Linux 배포판 버전이 어떤 태그를 지원하는지 대략적으로도 알려 줍니다. manylinux2010은 2010년 이후에 릴리스된 대부분의 배포판 버전에서 작동합니다. 그러나 이는 근사치일 뿐입니다. 실제 호환성 규칙은 아래에 정의되어 있으며, 일부 최신 배포판은 이를 충족하지 못할 수 있습니다.

manylinux2010 정책

다음 기준에 따라 linux 휠이 manylinux2010 태그에 적합한지가 결정됩니다.

  1. 휠에는 CentOS 6에서 지원되는 두 아키텍처 중 하나인 x86_64 또는 i686용으로 컴파일된 바이너리 실행 파일과 공유 객체만 포함할 수 있습니다. [5]
  2. 휠의 바이너리 실행 파일이나 공유 객체는 다음 허용 목록에 있는 라이브러리를 제외한 외부 제공 라이브러리에 링크해서는 안 됩니다.
    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.5libpanelw.so.5를 제외한 것과 동일합니다. [7] libpythonX.YPEP 513에 설명된 것과 동일한 이유로 포함할 수 없습니다.

    Fedora 30이 대신 libcrypt.so.2와 함께 릴리스된 후 libcrypt.so.1은 소급하여 허용 목록에서 제거되었습니다.

    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
  3. 휠에 버전이 지정된 심볼도 내보내는 허용 목록 라이브러리에 링크된 바이너리 실행 파일이나 공유 객체가 포함된 경우, 다음의 최대 버전에만 의존할 수 있습니다.:
    GLIBC_2.12
    CXXABI_1.3.3
    GLIBCXX_3.4.13
    GCC_4.5.0
    

    예를 들어, manylinux2010 휠에는 GLIBC_2.4 버전의 glibc 심볼을 필요로 하는 바이너리 아티팩트가 포함될 수 있습니다. 이는 최대 버전인 GLIBC_2.12보다 이른 버전이기 때문입니다.

  4. CPython 2의 모든 버전 또는 CPython 3.0부터 3.2까지의 버전용으로 빌드된 휠은 해당 휠의 유니코드 ABI를 나타내는 CPython ABI 태그를 반드시 포함해야 합니다. 따라서 Python 2용으로 빌드된 manylinux2010 휠은 UCS-4 ABI를 사용하는 인터프리터에 대해 빌드되었음을 나타내는 cpy27mu 태그나, UCS-2 ABI를 사용하는 인터프리터에 대해 빌드되었음을 나타내는 cpy27m 태그 중 하나를 반드시 포함해야 합니다. (PEP 3149, [9])
  5. 휠은 PyFPE_jbuf 심볼을 필요로 해서는 안 됩니다. 이는 --with-fpectl configure 플래그 없이 컴파일된 Python을 대상으로 빌드하여 달성합니다.

규격을 준수하는 휠의 컴파일

manylinux1과 마찬가지로, auditwheel 도구는 manylinux2010 Docker 컨테이너에서 pip wheel 또는 bdist_wheel로 빌드된 linux 휠에 manylinux2010 플랫폼 태그를 추가합니다.

Docker 이미지

CentOS 6을 기반으로 하는 두 개의 manylinux2010 Docker 이미지가 안정적으로 manylinux2010 휠로 변환할 수 있는 바이너리 linux 휠을 빌드하기 위해 제공됩니다. [10] x86_64 및 i686 이미지에는 최신 컴파일러 도구 모음(devtoolset-8gcc, 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”라는 동등한 메커니즘을 위해 오래전에 폐기되었습니다. vDSO에서는 커널이 최적화된 시스템 호출을 포함하는 재배치 가능한 가상 공유 객체를 각 프로세스에 대신 매핑합니다. [12]

vsyscall 페이지는 주소 공간 배치 무작위화(ASLR)에 참여하지 않기 때문에 심각한 보안 문제를 일으킵니다. 예측 가능한 위치와 콘텐츠로 인해 이 페이지는 반환 지향 프로그래밍 공격에 사용되는 가젯의 유용한 원천이 됩니다. [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 저장소에서 manylinux2010 이미지에 포함된 glibc 버전으로 vsyscall에 대한 모든 의존성 제거를 백포트하는 패치를 도출했습니다. [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 휠과의 하위 호환성

지정된 심볼 버전이 manylinux1 허용 목록에 포함된 라이브러리에 대해 상한을 구성한다는 점은 PEP 513에서 설명된 바와 같습니다. 이 PEP에서 manylinux2010에 대해 정의된 심볼 버전에도 동일하게 적용됩니다. 그 결과, manylinux1 휠은 manylinux2010 휠로 간주됩니다. 따라서 manylinux2010 플랫폼 태그를 인식하는 pip은, manylinux2010 휠을 사용할 수 없는 경우 – 명시적으로 설정된 경우에도 – manylinux2010 플랫폼에 manylinux1 휠을 설치합니다. [21]

PyPI 지원

PyPI는 manylinux1을 허용하는 것과 같은 방식으로 manylinux2010 플랫폼 태그를 포함하는 휠의 업로드를 허용해야 합니다. manylinux2010 휠의 호환성을 검증하려고 시도해서는 안 됩니다.

PEP 571에 대한 변경 사항 요약

이 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에는 영향을 미치지 않습니다.

참고 자료