Skip to content

Commit e6ffb51

Browse files
authored
Merge pull request #36 from seqeralabs/cursor/kasmvnc-qupath-f4f3
Add KasmVNC QuPath studio branch
2 parents 3f6b143 + b3c4d2d commit e6ffb51

26 files changed

Lines changed: 91 additions & 1626 deletions

.github/workflows/docker-pr.yml

Lines changed: 16 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -15,52 +15,22 @@ jobs:
1515
matrix: ${{ steps.set-matrix.outputs.matrix }}
1616
steps:
1717
- name: Checkout repository
18-
uses: actions/checkout@v4
18+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
1919

2020
- name: Detect changed Dockerfiles
2121
id: changes
22-
uses: dorny/paths-filter@v3
22+
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36
2323
with:
2424
filters: |
25-
ttyd:
26-
- 'ttyd/**'
27-
streamlit:
28-
- 'streamlit/**'
29-
cellxgene:
30-
- 'cellxgene/**'
31-
shiny:
32-
- 'shiny-simple-example/**'
33-
marimo:
34-
- 'marimo/**'
35-
napari:
36-
- 'kasmVNC/napari/**'
37-
qupath:
38-
- 'kasmVNC/qupath/**'
25+
kasmvnc_qupath:
26+
- '.seqera/**'
3927
4028
- name: Set matrix
4129
id: set-matrix
4230
run: |
4331
CONTAINERS="[]"
44-
if [[ "${{ steps.changes.outputs.ttyd }}" == "true" ]]; then
45-
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"ttyd","path":"./ttyd"}]')
46-
fi
47-
if [[ "${{ steps.changes.outputs.streamlit }}" == "true" ]]; then
48-
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"streamlit","path":"./streamlit"}]')
49-
fi
50-
if [[ "${{ steps.changes.outputs.cellxgene }}" == "true" ]]; then
51-
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"cellxgene","path":"./cellxgene"}]')
52-
fi
53-
if [[ "${{ steps.changes.outputs.shiny }}" == "true" ]]; then
54-
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"shiny","path":"./shiny-simple-example"}]')
55-
fi
56-
if [[ "${{ steps.changes.outputs.marimo }}" == "true" ]]; then
57-
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"marimo","path":"./marimo"}]')
58-
fi
59-
if [[ "${{ steps.changes.outputs.napari }}" == "true" ]]; then
60-
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"napari","path":"./kasmVNC/napari"}]')
61-
fi
62-
if [[ "${{ steps.changes.outputs.qupath }}" == "true" ]]; then
63-
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"qupath","path":"./kasmVNC/qupath"}]')
32+
if [[ "${{ steps.changes.outputs.kasmvnc_qupath }}" == "true" ]]; then
33+
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"kasmvnc-qupath","path":"./.seqera"}]')
6434
fi
6535
echo "matrix={\"container\":$CONTAINERS}" >> "$GITHUB_OUTPUT"
6636
@@ -79,44 +49,44 @@ jobs:
7949

8050
steps:
8151
- name: Checkout repository
82-
uses: actions/checkout@v4
52+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
8353

8454
- name: Log in to the Container registry
85-
uses: docker/login-action@v3
55+
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772
8656
with:
8757
registry: ${{ env.REGISTRY }}
8858
username: ${{ github.actor }}
8959
password: ${{ secrets.GHCR_TOKEN }}
9060

9161
- name: Set up Docker Buildx
92-
uses: docker/setup-buildx-action@v3
62+
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2
9363

9464
- name: Extract metadata
9565
id: meta
96-
uses: docker/metadata-action@v5
66+
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804
9767
with:
9868
images: ${{ env.REGISTRY }}/${{ github.repository }}/development
9969
tags: |
10070
type=ref,event=pr,prefix=${{ matrix.container.name }}-pr
10171
10272
- name: Build and push ${{ matrix.container.name }}
103-
uses: docker/build-push-action@v5
73+
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25
10474
with:
10575
context: ${{ matrix.container.path }}
10676
push: true
10777
platforms: linux/amd64
10878
tags: ${{ steps.meta.outputs.tags }}
10979
labels: ${{ steps.meta.outputs.labels }}
110-
cache-from: type=gha,scope=${{ matrix.container.name }}
111-
cache-to: type=gha,mode=max,scope=${{ matrix.container.name }}
80+
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ github.repository }}/development:${{ matrix.container.name }}-buildcache
81+
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ github.repository }}/development:${{ matrix.container.name }}-buildcache,mode=max
11282

11383
- name: Get image reference for scan
11484
id: scanref
11585
run: |
11686
echo "ref=${{ fromJSON(steps.meta.outputs.json).tags[0] }}" >> $GITHUB_OUTPUT
11787
11888
- name: Run security scan
119-
uses: aquasecurity/trivy-action@0.31.0
89+
uses: aquasecurity/trivy-action@76071ef0d7ec797419534a183b498b4d6366cf37
12090
with:
12191
image-ref: ${{ steps.scanref.outputs.ref }}
12292
format: "table"
@@ -137,7 +107,7 @@ jobs:
137107
fi
138108
139109
- name: Upload security scan results
140-
uses: actions/upload-artifact@v4
110+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
141111
if: always()
142112
with:
143113
name: trivy-scan-${{ matrix.container.name }}-${{ github.run_id }}
@@ -155,7 +125,7 @@ jobs:
155125
echo "- **Commit**: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY
156126
157127
- name: Comment on PR
158-
uses: actions/github-script@v7
128+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
159129
with:
160130
script: |
161131
const fs = require('fs');

.github/workflows/docker-release.yml

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,7 @@ on:
88
required: true
99
type: choice
1010
options:
11-
- ttyd
12-
- streamlit
13-
- cellxgene
14-
- shiny
15-
- marimo
16-
- napari
17-
- qupath
11+
- kasmvnc-qupath
1812
version:
1913
description: 'Version to release (e.g., 1.0.0)'
2014
required: true
@@ -38,34 +32,28 @@ jobs:
3832

3933
steps:
4034
- name: Checkout repository
41-
uses: actions/checkout@v4
35+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
4236

4337
- name: Set container path
4438
id: container
4539
run: |
4640
case "${{ inputs.container }}" in
47-
ttyd) echo "path=./ttyd" >> "$GITHUB_OUTPUT" ;;
48-
streamlit) echo "path=./streamlit" >> "$GITHUB_OUTPUT" ;;
49-
cellxgene) echo "path=./cellxgene" >> "$GITHUB_OUTPUT" ;;
50-
shiny) echo "path=./shiny-simple-example" >> "$GITHUB_OUTPUT" ;;
51-
marimo) echo "path=./marimo" >> "$GITHUB_OUTPUT" ;;
52-
napari) echo "path=./kasmVNC/napari" >> "$GITHUB_OUTPUT" ;;
53-
qupath) echo "path=./kasmVNC/qupath" >> "$GITHUB_OUTPUT" ;;
41+
kasmvnc-qupath) echo "path=./.seqera" >> "$GITHUB_OUTPUT" ;;
5442
esac
5543
5644
- name: Log in to the Container registry
57-
uses: docker/login-action@v3
45+
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772
5846
with:
5947
registry: ${{ env.REGISTRY }}
6048
username: ${{ github.actor }}
6149
password: ${{ secrets.GHCR_TOKEN }}
6250

6351
- name: Set up Docker Buildx
64-
uses: docker/setup-buildx-action@v3
52+
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2
6553

6654
- name: Extract metadata
6755
id: meta
68-
uses: docker/metadata-action@v5
56+
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804
6957
with:
7058
images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ inputs.container }}
7159
tags: |
@@ -76,7 +64,7 @@ jobs:
7664
org.opencontainers.image.licenses=MIT
7765
7866
- name: Build and push ${{ inputs.container }}
79-
uses: docker/build-push-action@v5
67+
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25
8068
with:
8169
context: ${{ steps.container.outputs.path }}
8270
push: true
@@ -85,11 +73,11 @@ jobs:
8573
CONNECT_CLIENT_VERSION=${{ inputs.connect_client_version || '0.9' }}
8674
tags: ${{ steps.meta.outputs.tags }}
8775
labels: ${{ steps.meta.outputs.labels }}
88-
cache-from: type=gha,scope=${{ inputs.container }}
89-
cache-to: type=gha,mode=max,scope=${{ inputs.container }}
76+
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ github.repository }}/${{ inputs.container }}:buildcache
77+
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ github.repository }}/${{ inputs.container }}:buildcache,mode=max
9078

9179
- name: Create GitHub Release
92-
uses: softprops/action-gh-release@v2
80+
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8
9381
with:
9482
tag_name: ${{ inputs.container }}/${{ inputs.version }}
9583
name: ${{ inputs.container }} ${{ inputs.version }}
Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,16 @@ LABEL org.opencontainers.image.source="https://github.com/seqeralabs/custom-stud
1414

1515
ENV TITLE="QuPath"
1616

17-
# KasmVNC Performance Optimizations
17+
# KasmVNC performance tuning for interactive desktop streaming
1818
ENV KASM_VNC_ENABLE_WEBP=1
1919
ENV KASM_VNC_JPEG_QUALITY=5
2020
ENV KASM_VNC_MAX_FRAME_RATE=30
2121
ENV KASM_VNC_THREADS=4
2222

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

44+
45+
# Create the X socket directory before KasmVNC drops privileges to the abc user.
46+
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
47+
4248
# Single-app mode: application launches directly, no desktop
4349
RUN echo "/opt/qupath/bin/QuPath" > /defaults/autostart
4450

@@ -56,8 +62,8 @@ COPY --from=connect /usr/bin/connect-client /usr/bin/connect-client
5662
# Install connect-client
5763
RUN /usr/bin/connect-client --install
5864

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

62-
# CMD bridges CONNECT_TOOL_PORT to KasmVNC's CUSTOM_PORT and launches the init
68+
# Bridge CONNECT_TOOL_PORT to KasmVNC's CUSTOM_PORT and launch the init system
6369
CMD ["/bin/bash", "-c", "export CUSTOM_PORT=${CONNECT_TOOL_PORT:-6901} && exec /init"]

.seqera/studio-config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
schemaVersion: "0.0.1"
2+
kind: "studio-config"
3+
session:
4+
template:
5+
kind: "dockerfile"
6+
dockerfile: "Dockerfile"

README.md

Lines changed: 48 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,70 @@
1-
# Custom Studios Examples
1+
# QuPath KasmVNC Studio Environment
22

3-
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.
3+
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.
44

5-
## Available Examples
5+
> 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.
66
7-
- [Marimo](marimo/README.md) - A reactive Python notebook environment
8-
- [CellxGene](cellxgene/README.md) - Interactive single-cell data visualization
9-
- [Streamlit](streamlit/README.md) - MultiQC visualization using Streamlit
10-
- [Shiny](shiny-simple-example/README.md) - Interactive data visualization with R Shiny
11-
- [TTYD](ttyd/README.md) - Interactive web-based terminal with bioinformatics tools
7+
## Quick Start
128

13-
## Prerequisites
9+
### Add from Git Repository
1410

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

20-
## Common Features
18+
### Alternative: Use Pre-built Image
2119

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

31-
## Deploying to Seqera Studios
24+
### Alternative: Build with Wave CLI
3225

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

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

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

51-
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.
38+
> **Note:** QuPath is x86_64 only. Build and run this Studio as `linux/amd64`.
5239
53-
### Examples with Environment Variables
40+
## Docker Image
5441

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

59-
### Examples without Environment Variables
44+
```
45+
ghcr.io/seqeralabs/custom-studios-examples/kasmvnc-qupath:latest
46+
```
6047

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

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

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

73-
## Documentation
58+
## Configuration
7459

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

83-
## Contributing
65+
## References
8466

85-
Feel free to contribute new examples or improvements to existing ones. Each example should:
86-
- Follow the established README structure
87-
- Include comprehensive documentation
88-
- Maintain consistency with common features
89-
- Provide clear prerequisites and deployment instructions
90-
- Include example data or clear data requirements
91-
92-
<!-- TODO Add a link to the blog post -->
67+
- [Seqera Studios: Custom Environments](https://docs.seqera.io/platform-cloud/studios/custom-envs)
68+
- [Seqera Studios: Add from Git Repository](https://docs.seqera.io/platform-cloud/studios/add-studio-git-repo)
69+
- [QuPath Documentation](https://qupath.readthedocs.io/)
70+
- [KasmVNC Documentation](https://kasmweb.com/kasmvnc)

0 commit comments

Comments
 (0)