Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .pipeline/OneBranch/stages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,13 @@ stages:
parameters:
osType: Linux
architecture: x64
manylinuxFlavor: '2_28'
publishArtifacts: false
- template: /.pipeline/templates/build-python-wheels-template.yml
parameters:
osType: Linux
architecture: x64
manylinuxFlavor: '2_34'
publishArtifacts: false
- template: /.pipeline/templates/build-python-wheels-template.yml
parameters:
Expand Down Expand Up @@ -208,6 +215,13 @@ stages:
parameters:
osType: Linux
architecture: arm64
manylinuxFlavor: '2_28'
publishArtifacts: false
- template: /.pipeline/templates/build-python-wheels-template.yml
parameters:
osType: Linux
architecture: arm64
manylinuxFlavor: '2_34'
publishArtifacts: false
- template: /.pipeline/templates/build-python-wheels-template.yml
parameters:
Expand Down
55 changes: 43 additions & 12 deletions .pipeline/templates/build-python-wheels-template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,41 @@ parameters:
type: boolean
default: true
displayName: 'Publish wheel artifacts (disable for OneBranch pipeline)'
- name: manylinuxFlavor
# Which manylinux glibc/OpenSSL ABI to target. Only consumed when osType=Linux.
# 2_28 -> AlmaLinux 8 base, libssl.so.1.1, glibc <= 2.28 (matches mssql-python's
# published Linux wheel tag and the RHEL 8 / Ubuntu 20.04 / Debian 11 family).
# 2_34 -> AlmaLinux 9 base, libssl.so.3, glibc <= 2.34 (RHEL 9+, Ubuntu 22.04+,
# Debian 12+).
default: '2_28'
type: string
values:
- '2_28'
- '2_34'

steps:
# Container-based builds for Linux (glibc - manylinux)
- ${{ if eq(parameters.osType, 'Linux') }}:
- script: |
set -euo pipefail

# Determine container image based on architecture
# Using pre-built images with Rust and maturin pre-installed for faster builds
MANYLINUX_FLAVOR="${{ parameters.manylinuxFlavor }}"

# Determine container image based on architecture and manylinux flavor.
# Using pre-built images with Rust and maturin pre-installed for faster builds.
if [ "${{ parameters.architecture }}" = "x64" ]; then
CONTAINER_IMAGE="ghcr.io/microsoft/mssql-rs/python-build/manylinux_2_34_x86_64_rust:latest"
CONTAINER_IMAGE="ghcr.io/microsoft/mssql-rs/python-build/manylinux_${MANYLINUX_FLAVOR}_x86_64_rust:latest"
MATURIN_COMPATIBILITY="manylinux_${MANYLINUX_FLAVOR}_x86_64"
elif [ "${{ parameters.architecture }}" = "ARM64" ] || [ "${{ parameters.architecture }}" = "arm64" ]; then
CONTAINER_IMAGE="ghcr.io/microsoft/mssql-rs/python-build/manylinux_2_34_aarch64_rust:latest"
CONTAINER_IMAGE="ghcr.io/microsoft/mssql-rs/python-build/manylinux_${MANYLINUX_FLAVOR}_aarch64_rust:latest"
MATURIN_COMPATIBILITY="manylinux_${MANYLINUX_FLAVOR}_aarch64"
else
echo "ERROR: Unsupported architecture: ${{ parameters.architecture }}"
exit 1
fi

echo "Building Python wheels in container: $CONTAINER_IMAGE"
echo "Maturin compatibility tag: $MATURIN_COMPATIBILITY"

mkdir -p "$(ob_outputDirectory)/wheels"

Expand All @@ -49,6 +65,7 @@ steps:
-v "$(ob_outputDirectory)/wheels:/workspace/target/wheels" \
-e "WORKSPACE_DIR=/workspace" \
-e "OUTPUT_DIR=/workspace/target/wheels" \
-e "MATURIN_COMPATIBILITY=$MATURIN_COMPATIBILITY" \
"$CONTAINER_IMAGE" \
bash /workspace/scripts/build-python-wheels-in-container.sh

Expand All @@ -63,7 +80,7 @@ steps:
fi
echo "✅ $WHEEL_COUNT wheels built successfully!"
ls -lh "$(ob_outputDirectory)/wheels"
displayName: 'Build Python wheels in manylinux container (${{ parameters.architecture }})'
displayName: 'Build Python wheels in manylinux_${{ parameters.manylinuxFlavor }} container (${{ parameters.architecture }})'
env:
CARGO_REGISTRIES_MSSQL_RS_PUBLIC_TOKEN: $(CARGO_REGISTRIES_MSSQL_RS_PUBLIC_TOKEN)
CARGO_REGISTRIES_MSSQL_RS_TOKEN: $(CARGO_REGISTRIES_MSSQL_RS_TOKEN)
Expand Down Expand Up @@ -121,14 +138,17 @@ steps:
# Using pre-built images with Rust and maturin pre-installed for faster builds
if [ "${{ parameters.architecture }}" = "x64" ]; then
CONTAINER_IMAGE="ghcr.io/microsoft/mssql-rs/python-build/musllinux_1_2_x86_64_rust:latest"
MATURIN_COMPATIBILITY="musllinux_1_2_x86_64"
elif [ "${{ parameters.architecture }}" = "ARM64" ] || [ "${{ parameters.architecture }}" = "arm64" ]; then
CONTAINER_IMAGE="ghcr.io/microsoft/mssql-rs/python-build/musllinux_1_2_aarch64_rust:latest"
MATURIN_COMPATIBILITY="musllinux_1_2_aarch64"
else
echo "ERROR: Unsupported architecture: ${{ parameters.architecture }}"
exit 1
fi

echo "Building Python wheels in container: $CONTAINER_IMAGE"
echo "Maturin compatibility tag: $MATURIN_COMPATIBILITY"

mkdir -p "$(ob_outputDirectory)/wheels"

Expand All @@ -137,6 +157,7 @@ steps:
-v "$(ob_outputDirectory)/wheels:/workspace/target/wheels" \
-e "WORKSPACE_DIR=/workspace" \
-e "OUTPUT_DIR=/workspace/target/wheels" \
-e "MATURIN_COMPATIBILITY=$MATURIN_COMPATIBILITY" \
"$CONTAINER_IMAGE" \
bash /workspace/scripts/build-python-wheels-in-container.sh

Expand Down Expand Up @@ -189,11 +210,21 @@ steps:
Get-ChildItem "$(ob_outputDirectory)\wheels" | Format-Table Name, Length
displayName: List all wheels

# Publish artifacts for CI/PR pipelines (not needed for OneBranch which uses ob_outputDirectory)
# Publish artifacts for CI/PR pipelines (not needed for OneBranch which uses ob_outputDirectory).
# Include the manylinux flavor in the artifact name on Linux so calling this template twice
# per arch (once per flavor) produces two distinct artifacts instead of colliding.
- ${{ if eq(parameters.publishArtifacts, true) }}:
- task: PublishPipelineArtifact@1
displayName: 'Publish Python wheels'
inputs:
targetPath: '$(ob_outputDirectory)/wheels'
artifact: 'wheels_${{ parameters.osType }}_${{ parameters.architecture }}'
publishLocation: 'pipeline'
- ${{ if eq(parameters.osType, 'Linux') }}:
- task: PublishPipelineArtifact@1
displayName: 'Publish Python wheels'
inputs:
targetPath: '$(ob_outputDirectory)/wheels'
artifact: 'wheels_${{ parameters.osType }}_${{ parameters.architecture }}_manylinux_${{ parameters.manylinuxFlavor }}'
publishLocation: 'pipeline'
- ${{ if ne(parameters.osType, 'Linux') }}:
- task: PublishPipelineArtifact@1
displayName: 'Publish Python wheels'
inputs:
targetPath: '$(ob_outputDirectory)/wheels'
artifact: 'wheels_${{ parameters.osType }}_${{ parameters.architecture }}'
publishLocation: 'pipeline'
12 changes: 12 additions & 0 deletions .pipeline/templates/validation-stages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ stages:
parameters:
osType: Linux
architecture: x64
manylinuxFlavor: '2_28'
- template: build-python-wheels-template.yml
parameters:
osType: Linux
architecture: x64
manylinuxFlavor: '2_34'
- template: build-python-wheels-template.yml
parameters:
osType: Alpine
Expand Down Expand Up @@ -166,6 +172,12 @@ stages:
parameters:
osType: Linux
architecture: ARM64
manylinuxFlavor: '2_28'
- template: build-python-wheels-template.yml
parameters:
osType: Linux
architecture: ARM64
manylinuxFlavor: '2_34'
- template: build-python-wheels-template.yml
parameters:
osType: Alpine
Expand Down
47 changes: 47 additions & 0 deletions containers/Dockerfile.PythonBuild.manylinux_2_28.arm64
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Pre-built Python wheel build image for manylinux_2_28 (ARM64)
# This image extends the official PyPA manylinux_2_28 image with pre-installed Rust
# and maturin to speed up CI builds by avoiding runtime installation of these tools.
# Base image is synced from quay.io/pypa to ACR via sync-container-images.yml pipeline
#
# manylinux_2_28 is based on AlmaLinux 8 (glibc 2.28, OpenSSL 1.1.1).
# Wheels built here link against libssl.so.1.1 / libcrypto.so.1.1 and use only
# glibc symbols up to GLIBC_2.28, matching RHEL 8, Ubuntu 20.04, Debian 11,
# Amazon Linux 2, and other distros that expose OpenSSL 1.1 at runtime.

FROM tdslibrs.azurecr.io/import/python-build/manylinux_2_28_aarch64:latest

# Install system dependencies required for building Python wheels with Rust extensions
RUN dnf install -y \
openssl-devel \
pkgconfig \
&& dnf clean all

# Install Rust toolchain (stable)
# This is installed system-wide so all Python versions can use it
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal
ENV PATH="/root/.cargo/bin:$PATH"

# Verify Rust installation
RUN rustc --version && cargo --version

# Find a Python installation to use for installing maturin
# manylinux images have multiple Python versions in /opt/python/
RUN PYTHON_BIN=$(ls /opt/python/cp312-*/bin/python 2>/dev/null | head -n1) && \
if [ -z "$PYTHON_BIN" ]; then \
PYTHON_BIN=$(ls /opt/python/cp311-*/bin/python 2>/dev/null | head -n1); \
fi && \
if [ -z "$PYTHON_BIN" ]; then \
PYTHON_BIN=$(ls /opt/python/cp310-*/bin/python 2>/dev/null | head -n1); \
fi && \
echo "Installing maturin using: $PYTHON_BIN" && \
$PYTHON_BIN -m pip install --no-cache-dir maturin && \
$PYTHON_BIN -m pip show maturin

# auditwheel is pre-installed in PyPA manylinux images (used for diagnostics;
# auditwheel=skip in pyproject.toml disables library vendoring)
RUN which auditwheel && auditwheel --version

WORKDIR /workspace

# Default command
CMD ["bash"]
47 changes: 47 additions & 0 deletions containers/Dockerfile.PythonBuild.manylinux_2_28.x64
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Pre-built Python wheel build image for manylinux_2_28 (x64)
# This image extends the official PyPA manylinux_2_28 image with pre-installed Rust
# and maturin to speed up CI builds by avoiding runtime installation of these tools.
# Base image is synced from quay.io/pypa to ACR via sync-container-images.yml pipeline
#
# manylinux_2_28 is based on AlmaLinux 8 (glibc 2.28, OpenSSL 1.1.1).
# Wheels built here link against libssl.so.1.1 / libcrypto.so.1.1 and use only
# glibc symbols up to GLIBC_2.28, matching RHEL 8, Ubuntu 20.04, Debian 11,
# Amazon Linux 2, and other distros that expose OpenSSL 1.1 at runtime.

FROM tdslibrs.azurecr.io/import/python-build/manylinux_2_28_x86_64:latest

# Install system dependencies required for building Python wheels with Rust extensions
RUN dnf install -y \
openssl-devel \
pkgconfig \
&& dnf clean all

# Install Rust toolchain (stable)
# This is installed system-wide so all Python versions can use it
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal
ENV PATH="/root/.cargo/bin:$PATH"

# Verify Rust installation
RUN rustc --version && cargo --version

# Find a Python installation to use for installing maturin
# manylinux images have multiple Python versions in /opt/python/
RUN PYTHON_BIN=$(ls /opt/python/cp312-*/bin/python 2>/dev/null | head -n1) && \
if [ -z "$PYTHON_BIN" ]; then \
PYTHON_BIN=$(ls /opt/python/cp311-*/bin/python 2>/dev/null | head -n1); \
fi && \
if [ -z "$PYTHON_BIN" ]; then \
PYTHON_BIN=$(ls /opt/python/cp310-*/bin/python 2>/dev/null | head -n1); \
fi && \
echo "Installing maturin using: $PYTHON_BIN" && \
$PYTHON_BIN -m pip install --no-cache-dir maturin && \
$PYTHON_BIN -m pip show maturin

# auditwheel is pre-installed in PyPA manylinux images (used for diagnostics;
# auditwheel=skip in pyproject.toml disables library vendoring)
RUN which auditwheel && auditwheel --version

WORKDIR /workspace

# Default command
CMD ["bash"]
28 changes: 24 additions & 4 deletions containers/PYTHON_WHEELS_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,24 @@ All images are hosted in your Azure Container Registry (`tdslibrs.azurecr.io`) t
### 🚀 Pre-built Images with Rust (Recommended for CI/CD)
These custom images extend official PyPA images with **Rust toolchain and maturin pre-installed** for faster builds.

#### Linux (glibc-based - Ubuntu, RHEL, Debian, etc.)
We maintain **two manylinux flavors** so we can ship a `.so` whose ABI honestly
matches the wheel tag. mssql-py-core wheels are repackaged into mssql-python,
which targets both OpenSSL 1.1 and OpenSSL 3 deployments, so we build for both:

#### Linux glibc 2.28 / OpenSSL 1.1 (AlmaLinux 8 base)
Wheel tag: `manylinux_2_28_<arch>`. Links to `libssl.so.1.1`, requires GLIBC ≤ 2.28.
Targets RHEL 8, Ubuntu 20.04, Debian 11, Amazon Linux 2.
- **x64**: `tdslibrs.azurecr.io/python-build/manylinux_2_28_x86_64_rust:latest`
- **ARM64**: `tdslibrs.azurecr.io/python-build/manylinux_2_28_aarch64_rust:latest`

#### Linux glibc 2.34 / OpenSSL 3 (AlmaLinux 9 base)
Wheel tag: `manylinux_2_34_<arch>`. Links to `libssl.so.3`, requires GLIBC ≤ 2.34.
Targets RHEL 9+, Ubuntu 22.04+, Debian 12+, Fedora 36+, Amazon Linux 2023.
- **x64**: `tdslibrs.azurecr.io/python-build/manylinux_2_34_x86_64_rust:latest`
- **ARM64**: `tdslibrs.azurecr.io/python-build/manylinux_2_34_aarch64_rust:latest`

#### Alpine (musl-based)
Wheel tag: `musllinux_1_2_<arch>`.
- **x64**: `tdslibrs.azurecr.io/python-build/musllinux_1_2_x86_64_rust:latest`
- **ARM64**: `tdslibrs.azurecr.io/python-build/musllinux_1_2_aarch64_rust:latest`

Expand Down Expand Up @@ -130,10 +143,16 @@ The Azure DevOps pipeline automatically builds wheels in containers:
```yaml
- template: templates/build-python-wheels-template.yml
parameters:
osType: Linux # Linux, Alpine, or MacOS
architecture: x64 # x64 or ARM64
osType: Linux # Linux, Alpine, MacOS, or Windows
architecture: x64 # x64 or ARM64
manylinuxFlavor: '2_28' # Only honored for osType=Linux: '2_28' or '2_34'
```

For Linux, call the template **twice** per arch (once with `manylinuxFlavor: '2_28'`,
once with `'2_34'`) to produce both flavors. The published artifacts include the
flavor in their name (`wheels_Linux_<arch>_manylinux_2_28`,
`wheels_Linux_<arch>_manylinux_2_34`) so they don't collide.

**What it does**:
1. Logs into ACR
2. Pulls the appropriate container image
Expand All @@ -148,7 +167,8 @@ The Azure DevOps pipeline automatically builds wheels in containers:

- **Purpose**: Build portable binary wheels that work across many Linux distributions
- **Standards**:
- `manylinux_2_28`: Compatible with glibc 2.28+ (Ubuntu 20.04+, RHEL 8+, Debian 10+)
- `manylinux_2_28`: Compatible with glibc 2.28+ (RHEL 8, Ubuntu 20.04, Debian 11, Amazon Linux 2). Links against OpenSSL 1.1.
- `manylinux_2_34`: Compatible with glibc 2.34+ (RHEL 9+, Ubuntu 22.04+, Debian 12+). Links against OpenSSL 3.
- `musllinux_1_2`: Compatible with musl 1.2+ (Alpine 3.13+)
- **Pre-installed**: Multiple Python versions (3.8-3.14), compilers, build tools
- **Official**: Maintained by PyPA at https://github.com/pypa/manylinux
Expand Down
20 changes: 20 additions & 0 deletions containers/build-python-images.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,24 @@ echo ""

cd "$SCRIPT_DIR"

# Build manylinux_2_28 x64 image (glibc 2.28, OpenSSL 1.1)
echo "==> Building manylinux_2_28 x64 image..."
docker build \
-f Dockerfile.PythonBuild.manylinux_2_28.x64 \
-t "${ACR_REGISTRY}/python-build/manylinux_2_28_x86_64_rust:latest" \
.
echo "✅ manylinux_2_28 x64 image built successfully"
echo ""

# Build manylinux_2_28 ARM64 image (glibc 2.28, OpenSSL 1.1)
echo "==> Building manylinux_2_28 ARM64 image..."
docker build \
-f Dockerfile.PythonBuild.manylinux_2_28.arm64 \
-t "${ACR_REGISTRY}/python-build/manylinux_2_28_aarch64_rust:latest" \
.
echo "✅ manylinux_2_28 ARM64 image built successfully"
echo ""

# Build manylinux x64 image
echo "==> Building manylinux x64 image..."
docker build \
Expand Down Expand Up @@ -62,6 +80,8 @@ echo "✅ All images built successfully!"
echo "======================================================"
echo ""
echo "Built images:"
echo " - ${ACR_REGISTRY}/python-build/manylinux_2_28_x86_64_rust:latest"
echo " - ${ACR_REGISTRY}/python-build/manylinux_2_28_aarch64_rust:latest"
echo " - ${ACR_REGISTRY}/python-build/manylinux_2_34_x86_64_rust:latest"
echo " - ${ACR_REGISTRY}/python-build/manylinux_2_34_aarch64_rust:latest"
echo " - ${ACR_REGISTRY}/python-build/musllinux_1_2_x86_64_rust:latest"
Expand Down
14 changes: 14 additions & 0 deletions containers/push-python-images.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ else
fi


# Push manylinux_2_28 x64 image
echo "==> Pushing manylinux_2_28 x64 image..."
docker push "${ACR_REGISTRY}/python-build/manylinux_2_28_x86_64_rust:latest"
echo "✅ manylinux_2_28 x64 image pushed"
echo ""

# Push manylinux_2_28 ARM64 image
echo "==> Pushing manylinux_2_28 ARM64 image..."
docker push "${ACR_REGISTRY}/python-build/manylinux_2_28_aarch64_rust:latest"
echo "✅ manylinux_2_28 ARM64 image pushed"
echo ""

# Push manylinux x64 image
echo "==> Pushing manylinux x64 image..."
docker push "${ACR_REGISTRY}/python-build/manylinux_2_34_x86_64_rust:latest"
Expand Down Expand Up @@ -59,6 +71,8 @@ echo "✅ All images pushed successfully!"
echo "======================================================"
echo ""
echo "Images available in ACR:"
echo " - ${ACR_REGISTRY}/python-build/manylinux_2_28_x86_64_rust:latest"
echo " - ${ACR_REGISTRY}/python-build/manylinux_2_28_aarch64_rust:latest"
echo " - ${ACR_REGISTRY}/python-build/manylinux_2_34_x86_64_rust:latest"
echo " - ${ACR_REGISTRY}/python-build/manylinux_2_34_aarch64_rust:latest"
echo " - ${ACR_REGISTRY}/python-build/musllinux_1_2_x86_64_rust:latest"
Expand Down
Loading
Loading