Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
9a210b5
Add user guide on simple server.
danielballan Feb 24, 2026
4ae00a1
Add section on readable storage
danielballan Feb 24, 2026
6411817
WIP server docs
danielballan Mar 17, 2026
cc8191b
Introduce 'catalog' config as alternative to 'trees'
danielballan Mar 18, 2026
d5a01df
Use dedicated config file for Containerfile
danielballan Mar 18, 2026
cc38ba5
WIP: docker-compse with PG and Redis
danielballan Mar 18, 2026
4b121b2
Fix order validators run in
danielballan Mar 19, 2026
73be7ad
Document docker-compose
danielballan Mar 19, 2026
49cad30
Include .env file explanation
danielballan Mar 19, 2026
7703e7d
Remove stray line
danielballan Mar 19, 2026
fd76284
Improve wording
danielballan Mar 19, 2026
caac448
Update location of monitoring compose file
danielballan Mar 19, 2026
8b8f849
cleanup
danielballan Mar 19, 2026
21fd70b
Make catalog and storage databases in PG
danielballan Mar 19, 2026
2ed92e0
Consistently use BaseSettings for all config models.
danielballan Mar 19, 2026
22c0985
Use 'secret' as valid placeholder.
danielballan Mar 19, 2026
0fcb431
Fix model validation issues with catalog and trees
danielballan Mar 19, 2026
99dc593
Config tests pass
danielballan Mar 19, 2026
eeda695
Test was testing invalid config. Fix it.
danielballan Mar 19, 2026
0b3215e
Expand comment explaining database creation.
danielballan Mar 19, 2026
f53825f
Add compose override example
danielballan Mar 19, 2026
a56977b
Consitent env var priority
danielballan Mar 20, 2026
22b378a
More details in docs
danielballan Mar 20, 2026
05f5b2b
First pass at single-node deployment complete
danielballan Mar 20, 2026
ba12d2d
Expose port
danielballan Mar 20, 2026
a89d39c
More comments on config.
danielballan Mar 20, 2026
0af7de7
Highlight the testing instructions at the top.
danielballan Mar 20, 2026
b7ad439
Fix path and use explicit scheme
danielballan Mar 20, 2026
7b1c664
Stub multi-node page and address warnings.
danielballan Mar 20, 2026
fabf738
Make persistent storage work smoothly for podman/docker.
danielballan Mar 23, 2026
e2086ff
More comments
danielballan Mar 23, 2026
30afcef
Add comprehensive server configuration example
danielballan Mar 23, 2026
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
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
TILED_SINGLE_USER_API_KEY=secret
POSTGRES_PASSWORD=secret
REDIS_PASSWORD=secret
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,7 @@ uv.lock
# pixi environments
.pixi/*
!.pixi/config.toml

# Do not commit overrides; these are for local changes.
compose.override.yaml
compose.override.yml
23 changes: 17 additions & 6 deletions Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,16 @@ RUN set -ex && \

FROM docker.io/python:${PYTHON_VERSION}-slim AS app_runtime
ARG PYTHON_VERSION=3.12
ARG APP_UID=999

# Add the application virtualenv to search path.
ENV PATH=/app/bin:$PATH

# Don't run your app as root.
# We will run the app as a user 'app' with a stable uid that is
# configurable via an ARG.
RUN set -ex && \
groupadd -r app && \
useradd -r -d /app -g app -N app
groupadd -r -g ${APP_UID} app && \
useradd -r -d /app -g app -u ${APP_UID} -N app

# See <https://hynek.me/articles/docker-signals/>.
STOPSIGNAL SIGINT
Expand All @@ -100,13 +102,14 @@ apt-get update -qy && \
apt-get install -qyy \
-o APT::Install-Recommends=false \
-o APT::Install-Suggests=false \
curl && \
curl gosu && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

RUN mkdir -p /deploy/config
RUN mkdir -p /storage && chown -R app:app /storage
COPY ./example_configs/single_catalog_single_user.yml /deploy/config
# Note: the ownership of storage will be set in the entrypoint.
RUN mkdir -p /storage
COPY ./example_configs/config_for_containerfile.yml /deploy/config
ENV TILED_CONFIG=/deploy/config

# Copy the pre-built `/app` directory to the runtime container
Expand All @@ -118,6 +121,7 @@ COPY share/tiled/templates /app/share/tiled/templates
# See tiled.utils.SHARE_TILED_PATH
RUN touch /app/share/tiled/.identifying_file_72628d5f953b4229b58c9f1f8f6a9a09

# Run smoke test as app so any cache files written to /app are owned by app.
USER app
WORKDIR /app

Expand All @@ -129,4 +133,11 @@ python -Ic 'import tiled'

EXPOSE 8000

# Switch back to root for entrypoint, which will gosu back to app
# after ensuring that /storage is writable by the app user.
USER root
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["docker-entrypoint.sh"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Won't chowning the volume from within the container change the ownership of the files outsdie the container, those mounted on /storage?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes. Same as would happen with PG or Redis.

It matters that this "storage" is all Tiled-controlled: the catalog, Zarr and Parquet data written by the server, etc. Any externally managed data would have to be separately managed, and explicitly/manually set with compatible permissions.


CMD ["tiled", "serve", "config", "--host", "0.0.0.0", "--port", "8000", "--scalable"]
74 changes: 74 additions & 0 deletions compose.dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
services:
tiled:
build:
context: .
dockerfile: Containerfile
environment:
- TILED_SINGLE_USER_API_KEY=${TILED_SINGLE_USER_API_KEY}
- TILED_CATALOG_URI=postgresql://tiled:${POSTGRES_PASSWORD}@postgres:5432/tiled_catalog
- TILED_CATALOG_WRITABLE_STORAGE=["file:///storage", "postgresql://tiled:${POSTGRES_PASSWORD}@postgres:5432/tiled_storage"]
- TILED_STREAMING_CACHE_URI=redis://:${REDIS_PASSWORD}@redis:6379
volumes:
- tiled_data:/storage
ports:
- 8000:8000
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- backend
healthcheck:
test: curl --fail http://localhost:8000/healthz || exit 1
interval: 60s
timeout: 10s
retries: 3
start_period: 30s

postgres:
image: docker.io/postgres:16
environment:
- POSTGRES_USER=tiled
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
# We create two databases, 'tiled_catalog' (metadata) and
# 'tiled_storage' (tabular data) below. But it is required to
# specify one here, so we use 'postgres' as a neutral default.
- POSTGRES_DB=postgres
volumes:
- postgres_data:/var/lib/postgresql/data
- ./initdb:/docker-entrypoint-initdb.d
restart: unless-stopped
networks:
- backend
healthcheck:
test: pg_isready -U tiled -d postgres
interval: 10s
timeout: 5s
retries: 5
start_period: 10s

redis:
image: docker.io/redis:7-alpine
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
restart: unless-stopped
networks:
- backend
healthcheck:
test: redis-cli -a ${REDIS_PASSWORD} ping
interval: 10s
timeout: 5s
retries: 5
start_period: 5s

volumes:
tiled_data:
postgres_data:
redis_data:

networks:
backend: {}
21 changes: 1 addition & 20 deletions docker-compose.yml → compose.monitoring.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,5 @@
---
services:
tiled:
image: ghcr.io/bluesky/tiled:0.2.5
environment:
- TILED_SINGLE_USER_API_KEY=${TILED_SINGLE_USER_API_KEY}
ports:
- 8000:8000
restart: unless-stopped
healthcheck:
test: curl --fail http://localhost:8000/healthz || exit 1
interval: 60s
timeout: 10s
retries: 3
start_period: 30s

# Below we additionally configure monitoring with Prometheus and Grafana.
# This is optional; it is not required for Tiled to function.

prometheus:
image: docker.io/prom/prometheus:v2.42.0
volumes:
Expand All @@ -42,9 +26,6 @@ services:
networks:
- backend
restart: unless-stopped

# Disable Grafana login screen for dev/demo.
# DO NOT USE THESE SETTINGS IN PRODUCTION.
environment:
GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION: "true"
GF_AUTH_ANONYMOUS_ENABLED: "true"
Expand Down
7 changes: 7 additions & 0 deletions compose.override.example.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
services:
tiled:
environment:
- TILED_CONFIG=/deploy/config
volumes:
- ./my-custom-config-dir:/deploy/config:ro
72 changes: 72 additions & 0 deletions compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
services:
tiled:
image: ghcr.io/bluesky/tiled:0.2.8
environment:
- TILED_SINGLE_USER_API_KEY=${TILED_SINGLE_USER_API_KEY}
- TILED_CATALOG_URI=postgresql://tiled:${POSTGRES_PASSWORD}@postgres:5432/tiled_catalog
- TILED_CATALOG_WRITABLE_STORAGE=["file:///storage", "postgresql://tiled:${POSTGRES_PASSWORD}@postgres:5432/tiled_storage"]
- TILED_STREAMING_CACHE_URI=redis://:${REDIS_PASSWORD}@redis:6379
volumes:
- tiled_data:/storage
ports:
- 8000:8000
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- backend
healthcheck:
test: curl --fail http://localhost:8000/healthz || exit 1
interval: 60s
timeout: 10s
retries: 3
start_period: 30s

postgres:
image: docker.io/postgres:16
environment:
- POSTGRES_USER=tiled
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
# We create two databases, 'tiled_catalog' (metadata) and
# 'tiled_storage' (tabular data) below. But it is required to
# specify one here, so we use 'postgres' as a neutral default.
- POSTGRES_DB=postgres
volumes:
- postgres_data:/var/lib/postgresql/data
- ./initdb:/docker-entrypoint-initdb.d
restart: unless-stopped
networks:
- backend
healthcheck:
test: pg_isready -U tiled -d postgres
interval: 10s
timeout: 5s
retries: 5
start_period: 10s

redis:
image: docker.io/redis:7-alpine
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
restart: unless-stopped
networks:
- backend
healthcheck:
test: redis-cli -a ${REDIS_PASSWORD} ping
interval: 10s
timeout: 5s
retries: 5
start_period: 5s

volumes:
tiled_data:
postgres_data:
redis_data:

networks:
backend: {}
Loading
Loading