Skip to content

Commit 5c73c9c

Browse files
committed
chore(airflow): Use uv from image
This is so we can use newer Python versions instead of being restricted by what is available in dnf. Copying over uv related changes from #1353, but modified a bit to avoid venv activation in each shell.
1 parent d15b998 commit 5c73c9c

2 files changed

Lines changed: 46 additions & 37 deletions

File tree

airflow/Dockerfile

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,29 @@
44
# - SecretsUsedInArgOrEnv : OPA_AUTH_MANAGER is a false positive and breaks the build.
55

66
ARG GIT_SYNC_VERSION
7+
ARG UV_VERSION
78

89
# For updated versions check https://github.com/kubernetes/git-sync/releases
910
# which should contain a image location (e.g. registry.k8s.io/git-sync/git-sync:v3.6.8)
1011
FROM oci.stackable.tech/sdp/git-sync/git-sync:${GIT_SYNC_VERSION} AS gitsync-image
1112

13+
FROM oci.stackable.tech/stackable/astral-sh/uv:${UV_VERSION} AS uv-image
14+
1215
FROM local-image/shared/statsd-exporter AS statsd_exporter-builder
1316

1417
FROM local-image/vector AS opa-auth-manager-builder
1518

1619
ARG OPA_AUTH_MANAGER
1720
ARG PYTHON_VERSION
18-
ARG UV_VERSION
21+
ARG STACKABLE_USER_UID
1922

2023
COPY airflow/opa-auth-manager/${OPA_AUTH_MANAGER} /tmp/opa-auth-manager
2124

2225
WORKDIR /tmp/opa-auth-manager
2326

24-
RUN <<EOF
25-
microdnf update
26-
microdnf install python${PYTHON_VERSION}-pip
27-
microdnf clean all
27+
COPY --from=uv-image --chown=${STACKABLE_USER_UID}:0 /uv /uvx /bin/
2828

29-
pip${PYTHON_VERSION} install --no-cache-dir uv==${UV_VERSION}
29+
RUN <<EOF
3030

3131
# This folder is required by the tests to set up an sqlite database
3232
mkdir /root/airflow
@@ -46,7 +46,6 @@ ARG STACKABLE_USER_UID
4646
ARG NODEJS_VERSION
4747
ARG S3FS_VERSION
4848
ARG CYCLONEDX_BOM_VERSION
49-
ARG UV_VERSION
5049

5150
# Airflow "extras" packages are listed here: https://airflow.apache.org/docs/apache-airflow/stable/extra-packages-ref.html
5251
# They evolve over time and thus belong to the version-specific arguments.
@@ -62,6 +61,8 @@ ARG AIRFLOW_EXTRAS_EXTERNAL_SERVICES=""
6261
ARG AIRFLOW_EXTRAS_LOCALLY_INSTALLED_SOFTWARE=""
6362
ARG AIRFLOW_EXTRAS_OTHER=""
6463

64+
COPY --from=uv-image --chown=${STACKABLE_USER_UID}:0 /uv /uvx /bin/
65+
6566
RUN microdnf module enable -y nodejs:${NODEJS_VERSION} && \
6667
microdnf update && \
6768
microdnf install \
@@ -78,10 +79,6 @@ RUN microdnf module enable -y nodejs:${NODEJS_VERSION} && \
7879
libpq-devel \
7980
openldap-devel \
8081
openssl-devel \
81-
python${PYTHON_VERSION} \
82-
python${PYTHON_VERSION}-devel \
83-
python${PYTHON_VERSION}-pip \
84-
python${PYTHON_VERSION}-wheel \
8582
# The airflow odbc provider can compile without the development files (headers and libraries) (see https://github.com/stackabletech/docker-images/pull/683)
8683
unixODBC \
8784
# Needed for Airflow UI assets
@@ -103,23 +100,28 @@ COPY --chown=${STACKABLE_USER_UID}:0 airflow/stackable/patches/${PRODUCT_VERSION
103100

104101
WORKDIR /stackable
105102

106-
RUN <<EOF
103+
# Set a cache directory so we can mount the cache for layers that use it.
104+
ENV UV_CACHE_DIR=/var/cache/uv
105+
# Don't use links because they won't work after `COPY --from` in the final stage.
106+
ENV UV_LINK_MODE=copy
107+
# Store the uv-managed Python inside /stackable/ so it gets included in the
108+
# COPY --from=airflow-build-image step. Without this, the venv symlinks would
109+
# point to /usr/local/share/uv/python/... which is not copied to the final image.
110+
ENV UV_PYTHON_INSTALL_DIR=/stackable/python
111+
112+
RUN uv venv --python "${PYTHON_VERSION}" --system-site-packages /stackable/app
113+
114+
# Instead of activating the environment each time
115+
ENV VIRTUAL_ENV=/stackable/app
116+
117+
RUN --mount=type=cache,target=/var/cache/uv <<EOF
107118

108119
# Compose comma-delimited AIRFLOW_EXTRAS
109120
AIRFLOW_EXTRAS="$AIRFLOW_EXTRAS_CORE,$AIRFLOW_EXTRAS_META,$AIRFLOW_EXTRAS_PROVIDER_APACHE,$AIRFLOW_EXTRAS_EXTERNAL_SERVICES,$AIRFLOW_EXTRAS_LOCALLY_INSTALLED_SOFTWARE,$AIRFLOW_EXTRAS_OTHER"
110121

111122
# Removing duplicates
112123
AIRFLOW_EXTRAS=$(echo "$AIRFLOW_EXTRAS" | tr ',' '\n' | awk 'NF > 0 {if (!seen[$0]++) print $0}' | tr '\n' ',' | sed 's/,$//')
113124

114-
python${PYTHON_VERSION} -m venv --system-site-packages /stackable/app
115-
116-
source /stackable/app/bin/activate
117-
118-
# Upgrade pip to the latest version
119-
# Also install uv to get support for build constraints
120-
pip install --no-cache-dir --upgrade pip
121-
pip install --no-cache-dir uv==${UV_VERSION}
122-
123125
# Pin virtualenv due to a breaking change in 21.0.0 which is pulled
124126
# in by hatch.
125127
# See https://github.com/pypa/hatch/issues/2193
@@ -134,6 +136,7 @@ if [ -d "./airflow-core" ]; then
134136
cd airflow-core/src/airflow/ui
135137

136138
# build front-end assets
139+
# TODO: Consider making the pnpm version an ARG
137140
npm install -g pnpm@10.18.2
138141
pnpm install --frozen-lockfile
139142
pnpm run build
@@ -143,13 +146,14 @@ if [ -d "./airflow-core" ]; then
143146
cd ../../..
144147
/root/.local/bin/hatch build -t wheel
145148
# First install the full apache-airflow package to get all dependencies including database drivers
146-
uv pip install --no-cache-dir apache-airflow[${AIRFLOW_EXTRAS}]==${PRODUCT_VERSION} --constraint /tmp/constraints.txt --build-constraints /tmp/build-constraints.txt
149+
uv pip install --python ${VIRTUAL_ENV}/bin/python apache-airflow[${AIRFLOW_EXTRAS}]==${PRODUCT_VERSION} --constraint /tmp/constraints.txt --build-constraints /tmp/build-constraints.txt
147150
# Then install the locally built core wheel to override the core package
148-
uv pip install --no-cache-dir dist/apache_airflow_core-${PRODUCT_VERSION}-py3-none-any.whl[${AIRFLOW_EXTRAS}] --constraint /tmp/constraints.txt --build-constraints /tmp/build-constraints.txt
151+
uv pip install --python ${VIRTUAL_ENV}/bin/python dist/apache_airflow_core-${PRODUCT_VERSION}-py3-none-any.whl[${AIRFLOW_EXTRAS}] --constraint /tmp/constraints.txt --build-constraints /tmp/build-constraints.txt
149152
else
150153
# Airflow 2.x
151154
# build front-end assets
152155
cd airflow/www
156+
# TODO: Consider making the yarn version an ARG
153157
npm install -g yarn@1.22.22
154158
yarn install --frozen-lockfile
155159
yarn run build
@@ -158,22 +162,22 @@ else
158162
cd ../..
159163
/root/.local/bin/hatch build -t wheel
160164
# First install the full apache-airflow package to get all dependencies including database drivers
161-
uv pip install --no-cache-dir apache-airflow[${AIRFLOW_EXTRAS}]==${PRODUCT_VERSION} --constraint /tmp/constraints.txt --build-constraints /tmp/build-constraints.txt
165+
uv pip install --python ${VIRTUAL_ENV}/bin/python apache-airflow[${AIRFLOW_EXTRAS}]==${PRODUCT_VERSION} --constraint /tmp/constraints.txt --build-constraints /tmp/build-constraints.txt
162166
# Then install the locally built wheel to override with patched version
163-
uv pip install --no-cache-dir dist/apache_airflow-${PRODUCT_VERSION}-py3-none-any.whl[${AIRFLOW_EXTRAS}] --constraint /tmp/constraints.txt --build-constraints /tmp/build-constraints.txt
167+
uv pip install --python ${VIRTUAL_ENV}/bin/python dist/apache_airflow-${PRODUCT_VERSION}-py3-none-any.whl[${AIRFLOW_EXTRAS}] --constraint /tmp/constraints.txt --build-constraints /tmp/build-constraints.txt
164168
fi
165169

166170
# Needed for pandas S3 integration to e.g. write and read csv and parquet files to/from S3
167171
# TODO: s3fs may already be installed via the s3fs extra and constraints. Check if this explicit install is still needed.
168-
uv pip install --no-cache-dir s3fs==${S3FS_VERSION} cyclonedx-bom==${CYCLONEDX_BOM_VERSION}
172+
uv pip install --python ${VIRTUAL_ENV}/bin/python s3fs==${S3FS_VERSION} cyclonedx-bom==${CYCLONEDX_BOM_VERSION}
169173
# Needed for OIDC
170-
uv pip install --no-cache-dir Flask_OIDC==2.2.0 Flask-OpenID==1.3.1
174+
uv pip install --python ${VIRTUAL_ENV}/bin/python Flask_OIDC==2.2.0 Flask-OpenID==1.3.1
171175

172-
uv pip install --no-cache-dir /tmp/opa_auth_manager-0.1.0-py3-none-any.whl
176+
uv pip install --python ${VIRTUAL_ENV}/bin/python /tmp/opa_auth_manager-0.1.0-py3-none-any.whl
173177

174178
# Create the SBOM for Airflow
175179
# Important: All `pip install` commands must be above this line, otherwise the SBOM will be incomplete
176-
cyclonedx-py environment --spec-version 1.5 --output-file /tmp/sbom.json
180+
${VIRTUAL_ENV}/bin/cyclonedx-py environment --spec-version 1.5 --output-file /tmp/sbom.json
177181
uv pip uninstall cyclonedx-bom
178182

179183
# Break circular dependencies by removing the apache-airflow dependency from the providers
@@ -215,8 +219,9 @@ LABEL name="Apache Airflow" \
215219
description="This image is deployed by the Stackable Operator for Apache Airflow."
216220

217221
ENV HOME=/stackable
218-
ENV AIRFLOW_USER_HOME_DIR=/stackable
219-
ENV PATH=$PATH:/bin:$HOME/app/bin
222+
ENV VIRTUAL_ENV=$HOME/app
223+
ENV AIRFLOW_USER_HOME_DIR=$HOME
224+
ENV PATH=$HOME/app/bin:$PATH:/bin
220225
ENV AIRFLOW_HOME=$HOME/airflow
221226

222227
COPY --from=airflow-build-image --chown=${STACKABLE_USER_UID}:0 /stackable/ ${HOME}/
@@ -230,14 +235,15 @@ COPY --from=gitsync-image --chown=${STACKABLE_USER_UID}:0 /git-sync ${HOME}/git-
230235

231236
COPY airflow/licenses /licenses
232237

238+
COPY --from=uv-image --chown=${STACKABLE_USER_UID}:0 /uv /uvx /bin/
239+
233240
# Update image and install needed packages
234241
RUN <<EOF
235242
microdnf update
236243

237244
# git: Needed for the gitsync functionality
238245
# openldap: Needed for authentication of clients against LDAP servers
239246
# openssh-clients: We need the openssh libs for the gitsync functionality (the clone target could be e.g. git@github.com:org/repo.git)
240-
# python: Airflow needs Python
241247
microdnf install \
242248
ca-certificates \
243249
cyrus-sasl \
@@ -248,7 +254,6 @@ microdnf install \
248254
openssh-clients \
249255
openssl-libs \
250256
openssl-pkcs11 \
251-
python${PYTHON_VERSION} \
252257
socat \
253258
unixODBC
254259
microdnf clean all

airflow/boil-config.toml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ s3fs-version = "2024.9.0"
1818
cyclonedx-bom-version = "7.3.0"
1919
tini-version = "0.19.0"
2020
# Bump to the latest release found here: https://github.com/astral-sh/uv/releases
21-
# TODO: mirror the uv images, and then use `COPY --from` instead of using pip.
21+
# Mirror uv (no `v` prefix) via https://github.com/stackabletech/docker-images/actions/workflows/mirror.yaml
22+
# Note: Mirrored to the `stackable` project, but should probably move elsewhere.
2223
uv-version = "0.11.19"
2324
airflow-extras-other = "async,amazon,celery,cncf.kubernetes,docker,dask,elasticsearch,ftp,grpc,hashicorp,http,ldap,google,google_auth,microsoft.azure,odbc,pandas,postgres,redis,sendgrid,sftp,slack,ssh,statsd,virtualenv,trino"
2425
opa-auth-manager = "airflow-2"
@@ -41,7 +42,8 @@ s3fs-version = "2024.9.0"
4142
cyclonedx-bom-version = "7.3.0"
4243
tini-version = "0.19.0"
4344
# Bump to the latest release found here: https://github.com/astral-sh/uv/releases
44-
# TODO: mirror the uv images, and then use `COPY --from` instead of using pip.
45+
# Mirror uv (no `v` prefix) via https://github.com/stackabletech/docker-images/actions/workflows/mirror.yaml
46+
# Note: Mirrored to the `stackable` project, but should probably move elsewhere.
4547
uv-version = "0.11.19"
4648

4749
# Airflow extras are defined in separate lists to make them easier to check against the links below.
@@ -85,7 +87,8 @@ s3fs-version = "2026.1.0"
8587
cyclonedx-bom-version = "7.3.0"
8688
tini-version = "0.19.0"
8789
# Bump to the latest release found here: https://github.com/astral-sh/uv/releases
88-
# TODO: mirror the uv images, and then use `COPY --from` instead of using pip.
90+
# Mirror uv (no `v` prefix) via https://github.com/stackabletech/docker-images/actions/workflows/mirror.yaml
91+
# Note: Mirrored to the `stackable` project, but should probably move elsewhere.
8992
uv-version = "0.11.19"
9093

9194
# Airflow extras are defined in separate lists to make them easier to check against the links below.
@@ -129,7 +132,8 @@ s3fs-version = "2026.3.0"
129132
cyclonedx-bom-version = "7.3.0"
130133
tini-version = "0.19.0"
131134
# Bump to the latest release found here: https://github.com/astral-sh/uv/releases
132-
# TODO: mirror the uv images, and then use `COPY --from` instead of using pip.
135+
# Mirror uv (no `v` prefix) via https://github.com/stackabletech/docker-images/actions/workflows/mirror.yaml
136+
# Note: Mirrored to the `stackable` project, but should probably move elsewhere.
133137
uv-version = "0.11.19"
134138

135139
# Airflow extras are defined in separate lists to make them easier to check against the links below.

0 commit comments

Comments
 (0)