Skip to content
Merged
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
62 changes: 16 additions & 46 deletions .github/workflows/docker-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,52 +15,22 @@ jobs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683

- name: Detect changed Dockerfiles
id: changes
uses: dorny/paths-filter@v3
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36
with:
filters: |
ttyd:
- 'ttyd/**'
streamlit:
- 'streamlit/**'
cellxgene:
- 'cellxgene/**'
shiny:
- 'shiny-simple-example/**'
marimo:
- 'marimo/**'
napari:
- 'kasmVNC/napari/**'
qupath:
- 'kasmVNC/qupath/**'
kasmvnc_qupath:
- '.seqera/**'

- name: Set matrix
id: set-matrix
run: |
CONTAINERS="[]"
if [[ "${{ steps.changes.outputs.ttyd }}" == "true" ]]; then
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"ttyd","path":"./ttyd"}]')
fi
if [[ "${{ steps.changes.outputs.streamlit }}" == "true" ]]; then
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"streamlit","path":"./streamlit"}]')
fi
if [[ "${{ steps.changes.outputs.cellxgene }}" == "true" ]]; then
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"cellxgene","path":"./cellxgene"}]')
fi
if [[ "${{ steps.changes.outputs.shiny }}" == "true" ]]; then
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"shiny","path":"./shiny-simple-example"}]')
fi
if [[ "${{ steps.changes.outputs.marimo }}" == "true" ]]; then
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"marimo","path":"./marimo"}]')
fi
if [[ "${{ steps.changes.outputs.napari }}" == "true" ]]; then
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"napari","path":"./kasmVNC/napari"}]')
fi
if [[ "${{ steps.changes.outputs.qupath }}" == "true" ]]; then
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"qupath","path":"./kasmVNC/qupath"}]')
if [[ "${{ steps.changes.outputs.kasmvnc_qupath }}" == "true" ]]; then
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"kasmvnc-qupath","path":"./.seqera"}]')
fi
echo "matrix={\"container\":$CONTAINERS}" >> "$GITHUB_OUTPUT"

Expand All @@ -79,44 +49,44 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683

- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GHCR_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804
with:
images: ${{ env.REGISTRY }}/${{ github.repository }}/development
tags: |
type=ref,event=pr,prefix=${{ matrix.container.name }}-pr

- name: Build and push ${{ matrix.container.name }}
uses: docker/build-push-action@v5
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25
with:
context: ${{ matrix.container.path }}
push: true
platforms: linux/amd64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.container.name }}
cache-to: type=gha,mode=max,scope=${{ matrix.container.name }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ github.repository }}/development:${{ matrix.container.name }}-buildcache
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ github.repository }}/development:${{ matrix.container.name }}-buildcache,mode=max

- name: Get image reference for scan
id: scanref
run: |
echo "ref=${{ fromJSON(steps.meta.outputs.json).tags[0] }}" >> $GITHUB_OUTPUT

- name: Run security scan
uses: aquasecurity/trivy-action@0.31.0
uses: aquasecurity/trivy-action@76071ef0d7ec797419534a183b498b4d6366cf37
with:
image-ref: ${{ steps.scanref.outputs.ref }}
format: "table"
Expand All @@ -137,7 +107,7 @@ jobs:
fi

- name: Upload security scan results
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
if: always()
with:
name: trivy-scan-${{ matrix.container.name }}-${{ github.run_id }}
Expand All @@ -155,7 +125,7 @@ jobs:
echo "- **Commit**: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY

- name: Comment on PR
uses: actions/github-script@v7
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
with:
script: |
const fs = require('fs');
Expand Down
32 changes: 10 additions & 22 deletions .github/workflows/docker-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@ on:
required: true
type: choice
options:
- ttyd
- streamlit
- cellxgene
- shiny
- marimo
- napari
- qupath
- kasmvnc-qupath
version:
description: 'Version to release (e.g., 1.0.0)'
required: true
Expand All @@ -38,34 +32,28 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683

- name: Set container path
id: container
run: |
case "${{ inputs.container }}" in
ttyd) echo "path=./ttyd" >> "$GITHUB_OUTPUT" ;;
streamlit) echo "path=./streamlit" >> "$GITHUB_OUTPUT" ;;
cellxgene) echo "path=./cellxgene" >> "$GITHUB_OUTPUT" ;;
shiny) echo "path=./shiny-simple-example" >> "$GITHUB_OUTPUT" ;;
marimo) echo "path=./marimo" >> "$GITHUB_OUTPUT" ;;
napari) echo "path=./kasmVNC/napari" >> "$GITHUB_OUTPUT" ;;
qupath) echo "path=./kasmVNC/qupath" >> "$GITHUB_OUTPUT" ;;
kasmvnc-qupath) echo "path=./.seqera" >> "$GITHUB_OUTPUT" ;;
esac

- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GHCR_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804
with:
images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ inputs.container }}
tags: |
Expand All @@ -76,7 +64,7 @@ jobs:
org.opencontainers.image.licenses=MIT

- name: Build and push ${{ inputs.container }}
uses: docker/build-push-action@v5
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25
with:
context: ${{ steps.container.outputs.path }}
push: true
Expand All @@ -85,11 +73,11 @@ jobs:
CONNECT_CLIENT_VERSION=${{ inputs.connect_client_version || '0.9' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ inputs.container }}
cache-to: type=gha,mode=max,scope=${{ inputs.container }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ github.repository }}/${{ inputs.container }}:buildcache
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ github.repository }}/${{ inputs.container }}:buildcache,mode=max

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8
with:
tag_name: ${{ inputs.container }}/${{ inputs.version }}
name: ${{ inputs.container }} ${{ inputs.version }}
Expand Down
16 changes: 11 additions & 5 deletions kasmVNC/qupath/Dockerfile → .seqera/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ LABEL org.opencontainers.image.source="https://github.com/seqeralabs/custom-stud

ENV TITLE="QuPath"

# KasmVNC Performance Optimizations
# KasmVNC performance tuning for interactive desktop streaming
ENV KASM_VNC_ENABLE_WEBP=1
ENV KASM_VNC_JPEG_QUALITY=5
ENV KASM_VNC_MAX_FRAME_RATE=30
ENV KASM_VNC_THREADS=4

# Install dependencies for QuPath
RUN apt-get update && apt-get install -y --no-install-recommends \
# Install dependencies for QuPath. The base image can carry stale third-party apt
# sources, so drop NodeSource before refreshing Ubuntu package indexes.
RUN rm -f /etc/apt/sources.list.d/nodesource*.list \
&& apt-get update && apt-get install -y --no-install-recommends \
wget \
xz-utils \
libgl1 \
Expand All @@ -39,6 +41,10 @@ RUN wget -q https://github.com/qupath/qupath/releases/download/v${QUPATH_VERSION
&& chmod +x /opt/qupath/bin/QuPath \
&& rm /tmp/qupath.tar.xz


# Create the X socket directory before KasmVNC drops privileges to the abc user.
RUN sed -i '/^exec s6-setuidgid/i mkdir -p /tmp/.X11-unix && chmod 1777 /tmp/.X11-unix' /etc/s6-overlay/s6-rc.d/svc-kasmvnc/run

# Single-app mode: application launches directly, no desktop
RUN echo "/opt/qupath/bin/QuPath" > /defaults/autostart

Expand All @@ -56,8 +62,8 @@ COPY --from=connect /usr/bin/connect-client /usr/bin/connect-client
# Install connect-client
RUN /usr/bin/connect-client --install

# Seqera Studios entrypoint (connect-client handles fusion filesystem)
# Seqera Studios entrypoint (connect-client handles Fusion filesystem)
ENTRYPOINT ["/usr/bin/connect-client", "--entrypoint"]

# CMD bridges CONNECT_TOOL_PORT to KasmVNC's CUSTOM_PORT and launches the init
# Bridge CONNECT_TOOL_PORT to KasmVNC's CUSTOM_PORT and launch the init system
CMD ["/bin/bash", "-c", "export CUSTOM_PORT=${CONNECT_TOOL_PORT:-6901} && exec /init"]
6 changes: 6 additions & 0 deletions .seqera/studio-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
schemaVersion: "0.0.1"
kind: "studio-config"
session:
template:
kind: "dockerfile"
dockerfile: "Dockerfile"
118 changes: 48 additions & 70 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,92 +1,70 @@
# Custom Studios Examples
# QuPath KasmVNC Studio Environment

This repository contains example Dockerfiles and configurations for custom Seqera Studio applications. Each example demonstrates how to create and deploy different types of interactive applications in Seqera Studios.
This branch contains the Seqera Studios configuration for running [QuPath](https://qupath.github.io/) with [KasmVNC](https://kasmweb.com/kasmvnc), making the QuPath desktop available through a browser in Seqera Platform.

## Available Examples
> This is a branch of the [custom-studios-examples](https://github.com/seqeralabs/custom-studios-examples) repository. Each branch contains a different custom Studio configuration. See the `master` branch for an overview of all available Studios.

- [Marimo](marimo/README.md) - A reactive Python notebook environment
- [CellxGene](cellxgene/README.md) - Interactive single-cell data visualization
- [Streamlit](streamlit/README.md) - MultiQC visualization using Streamlit
- [Shiny](shiny-simple-example/README.md) - Interactive data visualization with R Shiny
- [TTYD](ttyd/README.md) - Interactive web-based terminal with bioinformatics tools
## Quick Start

## Prerequisites
### Add from Git Repository

All examples in this repository require:
- [Docker](https://www.docker.com/) installed
- [Wave](https://docs.seqera.io/platform-cloud/wave/) configured in your Seqera Platform workspace
- Access to a container registry (public or Amazon ECR) for pushing your images
1. Navigate to **Studios** > **Add Studio** in your Seqera Platform workspace
2. Select **Git repository** as the source
3. Enter the repository URL: `https://github.com/seqeralabs/custom-studios-examples`
4. Select branch: `kasmvnc-qupath`
5. Select your compute environment
6. Click **Add** then **Start**

## Common Features
### Alternative: Use Pre-built Image

All examples in this repository:
- Are compatible with both local Docker testing and Seqera Studios
- Use the required Seqera base image and connect-client
- Include detailed setup and usage instructions
- Support data mounting via datalinks in Studios
- Are built for linux/amd64 platform compatibility
- Use multi-stage builds to include the connect-client
- Follow consistent container best practices
```
ghcr.io/seqeralabs/custom-studios-examples/kasmvnc-qupath:latest
```

## Deploying to Seqera Studios
### Alternative: Build with Wave CLI

All examples follow the same deployment process:
```bash
wave -f .seqera/Dockerfile --context .seqera --platform linux/amd64 --await --tower-token "$TOWER_ACCESS_TOKEN"
```

1. Select the **Studios** tab in your workspace
2. Click **Add Studio**
3. In the **General config** section:
- Select **Prebuilt container image** as the container template
- Enter your container image URI (e.g., `cr.seqera.io/scidev/your-example`)
- Set a **Studio name** and optional **Description**
4. Configure compute resources in the **Compute and Data** section:
- Select your compute environment
- Adjust CPU, GPU, and memory allocations as needed
- Mount any required data using the **Mount data** option
- Configure environment variables if the example supports them (see [Environment Variables](#environment-variables) section)
5. Review the configuration in the **Summary** section
6. Click **Add and start** to create and launch the Studio
## Features

## Environment Variables
- QuPath 0.6.0 bioimage analysis desktop
- Browser access through LinuxServer.io KasmVNC
- Single-app mode that launches QuPath directly
- KasmVNC WebP, quality, frame-rate, and thread tuning for interactive use
- Compatible with Seqera Studios custom environments and Data Link mounts

Some examples support environment variable configuration to customize data paths and application settings without modifying the container image. This makes those examples more flexible and reusable across different datasets and configurations.
> **Note:** QuPath is x86_64 only. Build and run this Studio as `linux/amd64`.

### Examples with Environment Variables
## Docker Image

Only the following examples support environment variable configuration:
- **CellxGene**: `DATASET_FILE`, `DATASET_TITLE` - Configure dataset path and display title
- **Shiny**: `DATA_PATH` - Configure data file path with automatic cloud storage path conversion
The container image is available at:

### Examples without Environment Variables
```
ghcr.io/seqeralabs/custom-studios-examples/kasmvnc-qupath:latest
```

These examples work with their default configurations and don't require environment variable setup:
- **Marimo**: Interactive Python notebook environment
- **Streamlit**: MultiQC visualization with web-based data loading interface
- **TTYD**: Web-based terminal with pre-installed bioinformatics tools
## Local Testing

### Using Environment Variables in Seqera Studios
```bash
cd .seqera
docker build --platform=linux/amd64 --build-arg CONNECT_CLIENT_VERSION=0.9 -t kasmvnc-qupath .
docker run --rm --platform linux/amd64 --shm-size=2g -p 6901:6901 --entrypoint /init kasmvnc-qupath
```

When deploying to Seqera Studios, you can configure environment variables in the **Compute and Data** section:
1. Expand the **Environment variables** section
2. Add key-value pairs for the variables you want to customize
3. The application will use these values instead of the defaults
QuPath will be available at http://localhost:6901.

## Documentation
## Configuration

- [Official documentation on building custom studio environments](https://docs.seqera.io/platform-cloud/studios/custom-envs#custom-containers)
- Each example's README contains specific instructions for:
- Building and testing locally
- Required dependencies and configurations
- Example-specific features and usage
- Data format requirements
- Customization options
| Variable | Default | Description |
|----------|---------|-------------|
| `CONNECT_TOOL_PORT` | Set by platform | KasmVNC web port in Seqera Studios |
| `CUSTOM_PORT` | `CONNECT_TOOL_PORT` or `6901` | KasmVNC web port used by the base image |

## Contributing
## References

Feel free to contribute new examples or improvements to existing ones. Each example should:
- Follow the established README structure
- Include comprehensive documentation
- Maintain consistency with common features
- Provide clear prerequisites and deployment instructions
- Include example data or clear data requirements

<!-- TODO Add a link to the blog post -->
- [Seqera Studios: Custom Environments](https://docs.seqera.io/platform-cloud/studios/custom-envs)
- [Seqera Studios: Add from Git Repository](https://docs.seqera.io/platform-cloud/studios/add-studio-git-repo)
- [QuPath Documentation](https://qupath.readthedocs.io/)
- [KasmVNC Documentation](https://kasmweb.com/kasmvnc)
Loading
Loading