Skip to content

Python-Ruby Http Distroless - #454

Open
cosmintanasa47 wants to merge 28 commits into
unikraft-cloud:mainfrom
cosmintanasa47:python-ruby-http-distroless
Open

cosmintanasa47 wants to merge 28 commits into
unikraft-cloud:mainfrom
cosmintanasa47:python-ruby-http-distroless

Conversation

@cosmintanasa47

Copy link
Copy Markdown

Here are http servers made with Python or Ruby - their distroless versions. Details in the commit messages.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

At least one new example is not runnable as-written (FastAPI distroless WORKDIR breaks src.server:app import) and the Flask+SQLite distroless app is missing a configured secret key despite using flash().

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR adds new “distroless” HTTP server examples (Ruby and multiple Python frameworks) for deployment on Unikraft Cloud, along with end-to-end tests that mirror the documented build/run steps.

Changes:

  • Introduces distroless example directories for Ruby 3.2 and Python 3.12 (stdlib, Flask, Flask+SQLite, FastAPI, Django).
  • Adds Dockerfiles/Kraftfiles/READMEs and minimal server implementations for each new example.
  • Adds end-to-end pytest coverage to validate each example serves expected content via Unikraft Cloud.
File summaries
File Description
httpserver-ruby3.2-distroless/test_httpserver-ruby3.2-distroless.py E2E test for Ruby distroless example.
httpserver-ruby3.2-distroless/server.rb Minimal Ruby TCP HTTP server implementation.
httpserver-ruby3.2-distroless/README.md Deployment and usage guide for Ruby distroless example.
httpserver-ruby3.2-distroless/Kraftfile Unikraft Cloud spec for Ruby distroless example.
httpserver-ruby3.2-distroless/Dockerfile Builds Ruby distroless rootfs including server.
httpserver-python3.12-flask3.0-sqlite-distroless/test_httpserver-python3.12-flask3.0-sqlite-distroless.py E2E test for Flask+SQLite distroless example.
httpserver-python3.12-flask3.0-sqlite-distroless/templates/post.html FlaskBlog post template.
httpserver-python3.12-flask3.0-sqlite-distroless/templates/index.html FlaskBlog index template.
httpserver-python3.12-flask3.0-sqlite-distroless/templates/edit.html FlaskBlog edit form template.
httpserver-python3.12-flask3.0-sqlite-distroless/templates/create.html FlaskBlog create form template.
httpserver-python3.12-flask3.0-sqlite-distroless/templates/base.html Base layout template for FlaskBlog.
httpserver-python3.12-flask3.0-sqlite-distroless/static/css/style.css Basic styling for FlaskBlog.
httpserver-python3.12-flask3.0-sqlite-distroless/server.py FlaskBlog app implementation with SQLite backend.
httpserver-python3.12-flask3.0-sqlite-distroless/schema.sql SQLite schema for posts table.
httpserver-python3.12-flask3.0-sqlite-distroless/requirements.txt Python dependencies for Flask+SQLite example.
httpserver-python3.12-flask3.0-sqlite-distroless/README.md Deployment and implementation guide for Flask+SQLite distroless example.
httpserver-python3.12-flask3.0-sqlite-distroless/Kraftfile Unikraft Cloud spec for Flask+SQLite distroless example.
httpserver-python3.12-flask3.0-sqlite-distroless/init_db.py Initializes the SQLite DB during image build.
httpserver-python3.12-flask3.0-sqlite-distroless/Dockerfile Distroless build copying Python runtime + app + DB.
httpserver-python3.12-flask3.0-sqlite-distroless/.dockerignore Reduces Docker build context for the example.
httpserver-python3.12-flask3.0-distroless/test_httpserver-python3.12-flask3.0-distroless.py E2E test for Flask distroless example.
httpserver-python3.12-flask3.0-distroless/server.py Minimal Flask “Hello, World!” server.
httpserver-python3.12-flask3.0-distroless/requirements.txt Flask dependency declaration.
httpserver-python3.12-flask3.0-distroless/README.md Deployment and usage guide for Flask distroless example.
httpserver-python3.12-flask3.0-distroless/Kraftfile Unikraft Cloud spec for Flask distroless example.
httpserver-python3.12-flask3.0-distroless/Dockerfile Distroless build for Flask example.
httpserver-python3.12-fastapi-0.121.3-distroless/test_httpserver-python3.12-fastapi-0.121.3-distroless.py E2E test for FastAPI distroless example.
httpserver-python3.12-fastapi-0.121.3-distroless/server.py Minimal FastAPI app.
httpserver-python3.12-fastapi-0.121.3-distroless/requirements.txt Dependencies for FastAPI app.
httpserver-python3.12-fastapi-0.121.3-distroless/README.md Deployment and usage guide for FastAPI distroless example.
httpserver-python3.12-fastapi-0.121.3-distroless/Kraftfile Unikraft Cloud spec for FastAPI distroless example.
httpserver-python3.12-fastapi-0.121.3-distroless/Dockerfile Distroless build copying Python runtime + app.
httpserver-python3.12-django5.0-distroless/test_httpserver-python3.12-django5.0-distroless.py E2E test for Django distroless example (admin endpoint).
httpserver-python3.12-django5.0-distroless/requirements.txt Django/bjoern/tzdata/etc dependencies.
httpserver-python3.12-django5.0-distroless/README.md Deployment and implementation guide for Django distroless example.
httpserver-python3.12-django5.0-distroless/manage.py Django manage.py entrypoint.
httpserver-python3.12-django5.0-distroless/main.py bjoern-based WSGI server runner.
httpserver-python3.12-django5.0-distroless/Kraftfile Unikraft Cloud spec for Django distroless example.
httpserver-python3.12-django5.0-distroless/helloworld/wsgi.py Django WSGI configuration.
httpserver-python3.12-django5.0-distroless/helloworld/urls.py Django URL configuration (admin).
httpserver-python3.12-django5.0-distroless/helloworld/settings.py Django settings for the example project.
httpserver-python3.12-django5.0-distroless/helloworld/asgi.py Django ASGI configuration.
httpserver-python3.12-django5.0-distroless/helloworld/init.py Django project package marker.
httpserver-python3.12-django5.0-distroless/Dockerfile Multi-stage build producing distroless Django image.
httpserver-python3.12-django5.0-distroless/.gitignore Ignores Python cache artifacts.
httpserver-python3.12-django5.0-distroless/.dockerignore Reduces Docker build context for the example.
httpserver-python3.12-distroless/test_httpserver-python3.12-distroless.py E2E test for stdlib Python distroless example.
httpserver-python3.12-distroless/server.py Minimal stdlib http.server-based implementation.
httpserver-python3.12-distroless/README.md Deployment and usage guide for stdlib Python distroless example.
httpserver-python3.12-distroless/Kraftfile Unikraft Cloud spec for stdlib Python distroless example.
httpserver-python3.12-distroless/Dockerfile Distroless python base image + server copy.
Review details

Suppressed comments (1)

httpserver-python3.12-distroless/README.md:210

  • This --image example uses the Flask image name (httpserver-python312-flask30) instead of this example's image name (httpserver-python312-distroless), so unikraft run would reference the wrong image.
  --image <my-org>/httpserver-python312-flask30:latest
  • Files reviewed: 50/51 changed files
  • Comments generated: 6
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread httpserver-python3.12-fastapi-0.121.3-distroless/Dockerfile
Comment thread httpserver-python3.12-flask3.0-sqlite-distroless/server.py
Comment thread httpserver-python3.12-distroless/README.md
Comment thread httpserver-python3.12-fastapi-0.121.3-distroless/README.md Outdated
Comment thread httpserver-python3.12-flask3.0-sqlite-distroless/requirements.txt
Comment thread httpserver-ruby3.2-distroless/README.md Outdated
Slightly modify to fit new distroless version.
Add multi-stage Dockerfile - first stage builds and the second executes.

Chosen openeuler/distroless-ruby:3.2.2-oe2403lts for runtime,
pinning to a specific SHA to avoid breaking changes from automatic updates.
Kept Kraftfile from non-distroless version.
Slightly modified non-distroless version's test file to fit
the new version.
Kept source file from non-distroless version.
Modified it to fit hte distroless version.
It uses the recommended image for distroless python and it
is set as nonroot for better security (less privilege - better).

It is single-stage because a builder stage would be redundant,
the executable is already built locally. To better understand,
this would be a multi-stage Dockerfile:

FROM python:3.13-slim-trixie AS builder

WORKDIR /src
COPY server.py /src/server.py

FROM gcr.io/distroless/python3-debian13:nonroot

WORKDIR /src
COPY --from=builder /src/server.py /src/server.py
…e Dockerfile

Replace the manual FROM scratch base with gcr.io/distroless/cc-debian12,
which provides a Google-maintained minimal glibc runtime (libc, ld-linux,
libssl/libcrypto, ca-certificates, /etc/passwd) instead of hand-copying
every system library.

The build stage still uses python:3.12-bookworm to compile bjoern's C
extension and install dependencies; only the required artifacts are
copied into the distroless final stage:
  - Python 3.12 interpreter + stdlib/site-packages (/usr/local/lib)
  - libpython3.12.so.1.0, explicitly placed under
    /usr/lib/x86_64-linux-gnu/ since the dynamic linker does not search
    /usr/local/lib by default and Unikraft Cloud boots the binary
    directly (Dockerfile ENV is not applied at runtime)
  - libev.so.4 (bjoern), libsqlite3.so.0 (Django ORM), libz.so.1
    (zlib, required transitively via binascii/base64), none of which
    are included in distroless/cc-debian12

Verified booting successfully on Unikraft Cloud after fixing two missing
shared library errors (libpython3.12.so.1.0, libz.so.1).
… files from non-distroless version

Those are exactly the same files as the ones in
httpserver-python3.12-django5.0 directory.
…t file

Slightly modified to fit the new distroless version.
Modified to fit new distroless version of python-django http server.
…i-stage Dockerfile

First stage install dependencies, the second runs the python scrypt.

Use gcr.io/distroless/cc-debian12 instead of python3-debian12 as the
runtime base image to resolve ABI compatibility issues with Python 3.12.

The python3-debian12 image provides Python 3.11 and the python3-debian13
image provides Python 3.13 by default, while thebuilder uses Python 3.12
(bookworm), leading to mismatched library paths and import errors for
modules like uvicorn. The distroless version was made to keep the
3.12 version of Python.

cc-debian12 includes glibc, libssl, libz, and libgcc, providing a more
flexible runtime environment for Python's native dependencies. The
Python interpreter and its libraries (libpython3.12.so.1.0) are copied
from the builder stage, ensuring version consistency.
…on test file

Modify to fit the new distroless version.
…ME.md

Modify to fit the new distroless version.
…dified files

Unmodified files from the non-distroless version: Kraftfile,
source file and python test file.
…files

Unmodified files from the non-distroless version: Kraftfile,
source file, requirements.txt.
Slightly modified to fit new distroless version.
… file

Slightly modified to fit new distroless version.
… Dockerfile

First stage resolves dependencies, the second one imports libraries
from the first stage and runs the server.

Use gcr.io/distroless/cc-debian12 instead of python3-debian12 as the
runtime base image to resolve ABI compatibility issues with Python 3.12.

The python3-debian12 image provides Python 3.11 and python3-debian13
image provides Python 3.13 by default, while the builder uses
Python 3.12 (bookworm), leading to mismatched library paths and import
errors for modules like uvicorn.

cc-debian12 includes glibc, libssl, libz, and libgcc, providing a more
flexible runtime environment for Python's native dependencies. The
Python interpreter and its libraries (libpython3.12.so.1.0) are copied
from the builder stage, ensuring version consistency.
…dified files

Unmodified files from non-distroless version: source file,
Kraftfile, init db scrypt, requirements.txt, schema.sql,
static and templates directories.
…kerignore

Non-distroless version's identic .dockerfile.
…ME.md

Slightly modified to fit new distroless version.
…on test file

Slightly modified from non-distroless version to fit new distroless
version.
…i-stage Dockerfile

First stage installs dependencies, second stage gets the libraries
and runs the server.

Use gcr.io/distroless/cc-debian12 instead of python3-debian12 as the
runtime base image to resolve ABI compatibility issues with Python 3.12.

The python3-debian12 image provides Python 3.11 and python3-debian13
image provides Python 3.13 by default, while the builder uses
Python 3.12 (bookworm), leading to mismatched library paths
and import errors for modules like uvicorn.

cc-debian12 includes glibc, libssl, libz, and libgcc, providing a more
flexible runtime environment for Python's native dependencies. The
Python interpreter and its libraries (libpython3.12.so.1.0) are copied
from the builder stage, ensuring version consistency.
@cosmintanasa47
cosmintanasa47 force-pushed the python-ruby-http-distroless branch from c5c8861 to 9ab88c8 Compare September 15, 2026 15:18
@cosmintanasa47

Copy link
Copy Markdown
Author

Fixed the typos. The first observation is wrong and I concluded that is wrong by testing the example and seeing it function exactly like it's original non-distroless version. There was also a recommandation to modify a README but the section that had to be modified wasn't directly about the distroless example, but for using pip, and it's copied from another non-distroless example. About modifying the other files that weren't part of the shift from scratch to distroless (like dockerfile and kraftfile), I assume that the previous version that was used like a template has it's source code and other config files correct and optimal. All the examples work when tested manually.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Critical security, startup, persistence, and runtime-version issues remain unresolved.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (14)

httpserver-python3.12-distroless/Dockerfile:1

  • This image is the Debian 13 python3 runtime (Python 3.13), while the example directory, test, and README identify it as Python 3.12. The published example therefore does not provide the advertised interpreter version; use a Python 3.12 runtime or rename/update all of the example's versioned references.
FROM gcr.io/distroless/python3-debian13:nonroot

httpserver-python3.12-distroless/README.md:193

  • This entire section is copied from the Flask example: it links to Flask, builds httpserver-python312-flask30, and assumes a requirements.txt that this project does not contain. Following it deploys a different example, so replace it with Python-specific guidance or remove it.
## Using `pip`

httpserver-python3.12-django5.0-distroless/README.md:141

  • There is no Dockerfile.distroless in this example; the file is named Dockerfile. As written, the customization instructions point readers to a nonexistent file.
You can set the username and password in the `Dockerfile.distroless` (more on this file later) to `unikraft/unikraft`.

httpserver-python3.12-django5.0-distroless/README.md:145

  • The warning acknowledges the insecure settings but still presents a public deployment path immediately above it, including a known admin password. This example should not be advertised as a reachable Cloud deployment until the fixed key/debug mode/default credential are removed or clearly isolated to a local-only setup.
> The example sets ALLOWED_HOSTS to * and runs in debug mode.
> For a production site, ensure you read the recommended deployment guides of the official Django project.

httpserver-python3.12-django5.0-distroless/helloworld/settings.py:28

  • Trusting https://*.unikraft.app accepts CSRF origins from every Unikraft app subdomain, not just this instance. A page hosted by another tenant could submit authenticated admin requests to this app. Configure the exact generated service origin at deployment instead of a global wildcard.
CSRF_TRUSTED_ORIGINS = ["https://*.unikraft.app"]

httpserver-python3.12-fastapi-0.121.3-distroless/requirements.txt:1

  • The example is explicitly named fastapi-0.121.3, but this unconstrained requirement installs whatever FastAPI is latest at build time, making the documented version and image behavior non-reproducible. Pin FastAPI (and the Uvicorn dependency) to the versions this example targets.
fastapi[standard]

httpserver-python3.12-flask3.0-distroless/README.md:182

  • The Dockerfile copies the application to /src/server.py and the Kraftfile runs that path, but this explanation says it is copied to /app/server.py. Following the documented path would leave the runtime instructions inconsistent with the image.
* `COPY ./server.py /app/server.py`: Copy the server implementation file (`server.py`) in the Docker filesystem (in `/app/server.py`).

httpserver-python3.12-flask3.0-sqlite-distroless/README.md:225

  • The app's directory is templates/ (and the implementation lists that same path above), but this customization instruction uses template/. Users following it will look in or edit the wrong directory.
    httpserver-python3.12-flask3.0-sqlite-distroless/README.md:113
  • The sample instance address shown above is lingering-orangutan-840mmdvd.fra.unikraft.app, but this command uses the unrelated young-night-5fpf0jj8 address. Copying the documented command therefore cannot query the instance just deployed.
    httpserver-python3.12-flask3.0-sqlite-distroless/README.md:180
  • The sentence uses initialized where the infinitive initialize is required.
    httpserver-python3.12-flask3.0-sqlite-distroless/README.md:48
  • The database is built at /app/database.db and the app exposes INSERT/UPDATE/DELETE routes, but this deployment uses an EROFS rootfs and does not request stateful storage or mount a writable volume. Mutations therefore cannot be reliably written or preserved across restarts. Add the appropriate stateful/volume configuration to both CLI examples, or move the database to a writable volume.
    httpserver-python3.12-flask3.0-sqlite-distroless/templates/base.html:9
  • The added static/css/style.css is never linked from this base template, so the app's own stylesheet (including the h1 rules) is never served. Add a url_for('static', filename='css/style.css') stylesheet link in the head.
    httpserver-python3.12-flask3.0-sqlite-distroless/templates/create.html:11
  • The form labels use for="title"/for="content", but neither control has the corresponding id; the same mismatch also exists in the edit form. Screen readers and label-based focus cannot associate these controls, so add matching id attributes to the input and textarea.
    httpserver-python3.12-flask3.0-sqlite-distroless/templates/edit.html:11
  • The edit form labels use for="title"/for="content", but neither control has the corresponding id; the same mismatch exists in create.html. Screen readers and label-based focus cannot associate these controls, so add matching id attributes to the input and textarea.
  • Files reviewed: 50/51 changed files
  • Comments generated: 8
  • Review effort level: Lite

Comment on lines +26 to +27
RUN python3 manage.py migrate && \
DJANGO_SUPERUSER_PASSWORD=unikraft python3 manage.py createsuperuser --noinput --username unikraft --email mail@example.com

rootfs:
source: ./Dockerfile
format: erofs
Use `curl` to query the Unikraft Cloud instance of the Django web app server:

```bash
curl https://dawn-sound-n5wrkxi2.fra.unikraft.app
Comment on lines +23 to +26
SECRET_KEY = "django-insecure-gb8wk^txj5ag6)q_wh82@i0nwhw(jhc!ga7!ux#yz^0hsb@=9g"

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
source: ./Dockerfile
format: erofs

cmd: ["/usr/bin/python3", "-m", "uvicorn", "src.server:app", "--host", "0.0.0.0", "--port", "8080"]

rootfs:
source: ./Dockerfile
format: erofs
conn.execute('DELETE FROM posts WHERE id = ?', (id,))
conn.commit()
conn.close()
flash('"{}" was successfully deleted!'.format(post['title']))
`source: ./Dockerfile` means the filesystem is built using the `Dockerfile`.
`format: erofs` means the filesystem type is [EROFS](https://erofs.docs.kernel.org/).

* `cmd: ["/usr/bin/python3", "-m", "uvicorn", "src.server:app", "--host", "0.0.0.0", "--port", "8080"]`: Use this as the starting command of the instance.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants