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
46 changes: 46 additions & 0 deletions examples/apps/Dockerfile.flyte_binary
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# syntax=docker/dockerfile:1.10
FROM ghcr.io/astral-sh/uv:0.8.13 AS uv
FROM ghcr.io/flyteorg/flyte-demo:nightly

# k3s rootfs lacks /usr/bin and has no package manager, so layer tooling by hand.
RUN mkdir -p /usr/bin /opt
COPY --from=uv /uv /usr/bin/uv

# Download a self-contained glibc Python. Must match the target platform — this
# image runs on linux/amd64, so use x86_64-unknown-linux-gnu.
ADD https://github.com/astral-sh/python-build-standalone/releases/download/20250723/cpython-3.11.13+20250723-x86_64-unknown-linux-gnu-install_only.tar.gz /tmp/python.tgz
RUN tar -xzf /tmp/python.tgz -C /opt && rm /tmp/python.tgz

# Point the dynamic linker at the image's bundled glibc and stub the libs
# python-build-standalone expects but pg-glibc doesn't ship (libutil, libnsl
# were merged into libc in glibc 2.34; libresolv similarly).
RUN ln -sf /usr/lib/pg-glibc/libc.so.6 /usr/lib/pg-glibc/libutil.so.1 \
&& ln -sf /usr/lib/pg-glibc/libc.so.6 /usr/lib/pg-glibc/libnsl.so.1 \
&& ln -sf /usr/lib/pg-glibc/libc.so.6 /usr/lib/pg-glibc/libresolv.so.2

ENV LD_LIBRARY_PATH=/usr/lib/pg-glibc
ENV UV_PYTHON=/opt/python/bin/python3
ENV PATH="/opt/venv/bin:/opt/python/bin:/usr/bin:${PATH}"

# pyqwest (Rust HTTP client used by flyte) can't autodiscover the CA bundle in
# this non-standard rootfs. Point it explicitly.
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
ENV SSL_CERT_DIR=/etc/ssl/certs

# Install flyte from a specific git ref so we can test branch changes. Override
# at build time with --build-arg FLYTE_SDK_REF=<branch|tag|sha>. We use a GitHub
# snapshot tarball rather than git+https because the base image has no git.
# SETUPTOOLS_SCM_PRETEND_VERSION_FOR_FLYTE is required because GitHub archive
# tarballs contain no .git directory and no PKG-INFO, so setuptools-scm cannot
# infer a version.
ARG FLYTE_SDK_REF=oss-binary-app

# Pass --python explicitly so uv never tries to probe the system libc (which
# fails here because busybox shells are statically linked).
RUN SETUPTOOLS_SCM_PRETEND_VERSION_FOR_FLYTE=0.0.0+${FLYTE_SDK_REF} \
/usr/bin/uv venv /opt/venv --python=/opt/python/bin/python3 \
&& SETUPTOOLS_SCM_PRETEND_VERSION_FOR_FLYTE=0.0.0+${FLYTE_SDK_REF} \
/usr/bin/uv pip install --python=/opt/venv/bin/python \
"flyte @ https://github.com/flyteorg/flyte-sdk/archive/${FLYTE_SDK_REF}.tar.gz"

WORKDIR /root
67 changes: 67 additions & 0 deletions examples/apps/flyte_binary_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""A basic app that uses the built-in Streamlit `hello` app."""

from pathlib import Path

from kubernetes.client.models import (
V1Capabilities,
V1Container,
V1PodSpec,
V1SecurityContext,
)

import flyte
import flyte.app

# Built via a custom Dockerfile because flyte-demo:nightly is a k3s rootfs:
# no /usr/bin, static busybox shells, and only a partial glibc bundled for
# Postgres. The Dockerfile pulls python-build-standalone, points it at the
# bundled glibc, and installs flyte.
image = flyte.Image.from_dockerfile(
file=Path(__file__).parent / "Dockerfile.flyte_binary",
registry="ghcr.io/flyteorg",
name="flyte-demo",
)

# The `App` declaration.
# Uses the `ImageSpec` declared above.
# In this case we do not need to supply any app code
# as we are using the built-in Streamlit `hello` app.
# k3s-in-a-pod needs to write /sys/fs/cgroup, create netns, run iptables, etc.
# Ask for a privileged container + SYS_ADMIN. The primary container name must
# be "app" (see src/flyte/app/_runtime/app_serde.py:110); the SDK merges the
# runtime-generated image/command/resources into this container, so we only
# set the security bits here. If the Union cluster's admission policy forbids
# privileged pods, the deploy will fail with a clear admission error.
privileged_pod_template = flyte.PodTemplate(
primary_container_name="app",
pod_spec=V1PodSpec(
containers=[
V1Container(
name="app",
security_context=V1SecurityContext(
privileged=True,
allow_privilege_escalation=True,
run_as_user=0,
capabilities=V1Capabilities(add=["SYS_ADMIN", "NET_ADMIN"]),
),
),
],
),
)

app_env = flyte.app.AppEnvironment(
name="flyte-oss-binary",
image=image,
port=30080,
# Run the same entrypoint the base image ships with (k3d wrapper that
# boots k3s + flyte-demo-bootstrap).
command=["/bin/k3d-entrypoint.sh", "server", "--disable=servicelb", "--disable=metrics-server"],
resources=flyte.Resources(cpu="8", memory="8Gi"),
pod_template=privileged_pod_template,
)


if __name__ == "__main__":
flyte.init_from_config()
d = flyte.deploy(app_env)
print(d[0])
2 changes: 1 addition & 1 deletion src/flyte/_code_bundle/bundle.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ async def download_bundle(bundle: CodeBundle) -> pathlib.Path:
# downloaded data should be copied into this directory. We do this to account for a difference in behavior in
# fsspec, which requires a trailing slash in case of pre-existing directory.
args = [
"-xvf",
"-xzvf",
str(downloaded_bundle),
"-C",
str(dest),
Expand Down
Loading