Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Docker Deployment #11

Merged
merged 13 commits into from
Nov 4, 2024
4 changes: 2 additions & 2 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"codespaces": {
"openFiles": [
"README.md",
"app.py"
"conda_metadata_app/pages/main_page.py"
]
},
"vscode": {
Expand All @@ -19,7 +19,7 @@
},
"updateContentCommand": "[ -f packages.txt ] && sudo apt update && sudo apt upgrade -y && sudo xargs apt install -y <packages.txt; [ -f requirements.txt ] && pip3 install --user -r requirements.txt; pip3 install --user streamlit; echo '✅ Packages installed and Requirements met'",
ytausch marked this conversation as resolved.
Show resolved Hide resolved
"postAttachCommand": {
"server": "streamlit run app.py --server.enableCORS false --server.enableXsrfProtection false"
"server": "streamlit run app_proxy.py --server.enableCORS false --server.enableXsrfProtection false"
},
"portsAttributes": {
"8501": {
Expand Down
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Dockerfile
.pixi/
.github/
50 changes: 50 additions & 0 deletions .github/workflows/container.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Container
on:
push:
branches: [main]
pull_request:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build-docker:
runs-on: ubuntu-latest
name: Docker

permissions:
contents: read
packages: write

outputs:
digest: ${{ steps.build-and-push.outputs.digest }}

steps:
- name: Checkout branch
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0

- name: Login into GHCR
if: github.ref_name == 'main'
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Docker meta
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1
id: meta
with:
images: |
ghcr.io/${{ github.repository }}
tags: | # no explicit versioning, always overwrite latest
type=raw,value=latest,enable=true
- name: Build and push
id: build-and-push
uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0
with:
push: ${{ github.ref_name == 'main' }}
file: Dockerfile
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
27 changes: 27 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
FROM ghcr.io/prefix-dev/pixi:0.31.0 AS build

RUN apt update
RUN apt install -y git

ytausch marked this conversation as resolved.
Show resolved Hide resolved
COPY . /app
WORKDIR /app

RUN ./docker/install.sh

FROM ubuntu:24.04 AS production

COPY --from=build /app/.pixi/envs/default /app/.pixi/envs/default
COPY --from=build /app/app_proxy.py /app
COPY --from=build /app/app_config.toml /app
COPY --from=build --chmod=0555 /entrypoint.sh /

WORKDIR /app
EXPOSE 8080
ENTRYPOINT ["/entrypoint.sh"]
CMD ["streamlit", \
"run", \
"--server.headless=true", \
"--global.developmentMode=false", \
"--browser.gatherUsageStats=false", \
"--server.port=8080", \
"app_proxy.py"]
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,33 @@ A streamlit app to query metadata from conda packages.
![Main Screenshot](docs/assets/main_screenshot_light.png#gh-light-mode-only)

## Development
Start by running `pixi run postinstall` to install the project locally.

Use `pixi run dev` to run the app in development mode, and `pixi run deploy` to run a production version of the app.

If you modified the configuration schema (see below), use `pixi run schema` to update the schema.

### Dependencies
Please note that this project defines dependencies in both a pixi project file (`pixi.toml`) and a `requirements.txt` file.
The pixi project is used for local development and the Docker image, while the `requirements.txt` file is used for the
public Streamlit cloud deployment.

## Custom Configuration

Refer to the [Configuration Documentation](docs/configuration.md) for more information on how to customize the app.
Refer to the [Configuration Documentation](docs/configuration.md) for more information on how to customize the app.

## Docker Deployment
A public Docker image of this app is available. To run the Docker app, execute the following command:

```bash
docker run -p 8080:8080 ghcr.io/Quansight-Labs/conda-metadata-app:latest
```

By default, the image uses the default configuration located at [app_config.toml](app_config.toml).

To supply a custom configuration, mount a file to `/app/app_config.toml`:

```bash
docker run -p 8080:8080 -v /path/to/app_config.toml:/app/app_config.toml ghcr.io/Quansight-Labs/conda-metadata-app:latest
```
Note that if you use environment variables or secret files for credentials, you will need to set/mount those as well.
8 changes: 8 additions & 0 deletions app_proxy.py
ytausch marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
This workaround is needed because streamlit does not support an app from a module.
https://github.com/streamlit/streamlit/issues/662#issuecomment-553356419
"""

import runpy

runpy.run_module("conda_metadata_app.app", run_name="__main__", alter_sys=True)
Empty file added conda_metadata_app/__init__.py
Empty file.
24 changes: 24 additions & 0 deletions conda_metadata_app/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from pathlib import Path

import streamlit as st

"""
If deploying a streamlit app as a Python module, we cannot use
the automatic pages/ subpages. Instead, we need to define the
pages manually.
"""

pages_dir = Path(__file__).parent / "pages"

main_page = st.Page(
pages_dir / "main_page.py",
title="app",
)

search_by_file_path_page = st.Page(
pages_dir / "search_by_file_path_page.py",
title="Search By File Path",
)
ytausch marked this conversation as resolved.
Show resolved Hide resolved

pg = st.navigation([main_page, search_by_file_path_page])
ytausch marked this conversation as resolved.
Show resolved Hide resolved
pg.run()
File renamed without changes.
Empty file.
7 changes: 3 additions & 4 deletions app.py → conda_metadata_app/pages/main_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
from rattler.platform import PlatformLiteral
from requests.auth import HTTPBasicAuth

from app_config import AppConfig, Channel, PackageDiscoveryChoice, ArchSubdirDiscoveryChoice, ArchSubdirList, \
ArtifactDiscoveryChoice, MetadataRetrieval, Secret
from conda_metadata_app.app_config import (AppConfig, Channel, PackageDiscoveryChoice, ArchSubdirDiscoveryChoice,
ArchSubdirList, ArtifactDiscoveryChoice, MetadataRetrieval, Secret)
from conda_metadata_app.version_order import VersionOrder

if not os.environ.get("CACHE_DIR"):
from conda_oci_mirror import defaults
Expand All @@ -36,8 +37,6 @@
from streamlit.logger import get_logger
from xml.etree import ElementTree as ET

from version_order import VersionOrder


yaml = YAML(typ="safe")
yaml.allow_duplicate_keys = True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import streamlit as st
from streamlit_searchbox import st_searchbox

from app import app_config
from conda_metadata_app.app_config import AppConfig


@st.cache_resource(ttl="15m", max_entries=100)
Expand Down Expand Up @@ -49,7 +49,7 @@ def find_artifacts_by_path(path):
initial_sidebar_state="collapsed",
)

if not app_config().enable_filepath_search:
if not AppConfig().enable_filepath_search:
st.error("File path search is disabled in the app configuration.")
st.stop()
ytausch marked this conversation as resolved.
Show resolved Hide resolved

Expand Down
File renamed without changes.
10 changes: 10 additions & 0 deletions docker/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash

set -eux

pixi run -e build build-wheel
pixi install -e default --locked
pixi run -e default postinstall-production
echo "#!/bin/sh" > /entrypoint.sh
pixi shell-hook -e default -s bash >> /entrypoint.sh
echo 'exec "$@"' >> /entrypoint.sh
Loading