Run Tiled Server in a Container

There is an official Tiled container image for use with Docker or podman.

Download the Tiled container image.

docker pull ghcr.io/bluesky/tiled:latest

It is best practice to use a specific tag instead of latest. See the list of tiled image versions on GitHub for tags.

Note

Some of the examples below set an environment variable TILED_SINGLE_USER_API_KEY to secret, as a placeholder. For actual use, use a difficult-to-guess secret. Two equally good ways to generate a secure secret…

With openssl:

openssl rand -hex 32

With python:

python -c "import secrets; print(secrets.token_hex(32))"

Example: A writable catalog

docker run \
  -p 8000:8000 \
  -e TILED_SINGLE_USER_API_KEY=secret \
  ghcr.io/bluesky/tiled:latest

The data and database are inside the container and will not persist outside it. Read on to persist it.

Example: A persistent writable catalog

We will create and mount a local directory, ./storage which will be used to hold uploaded data and # a (SQLite) database to index the metadata.

mkdir storage/

docker run \
  -p 8000:8000 \
  -e TILED_SINGLE_USER_API_KEY=secret \
  -v ./storage:/storage ghcr.io/bluesky/tiled:latest

Example: Serve a directory of existing files

We will point Tiled at a (read-only) directory of files and ask it to crawl and serve them. If you don’t have scientific data files at hand to try this with, you can quickly generate some with:

# Optional: Generate sample files... TIFF, Excel, HDF5, etc.
python -m tiled.examples.generate_files data/

Quick Start (Not Scalable)

This approach is nice for development and rapid iteration. It indexes the files at server startup.

docker run \
  -p 8000:8000 \
  -e TILED_SINGLE_USER_API_KEY=secret \
  -v ./data:/data:ro \
  ghcr.io/bluesky/tiled:latest \
  tiled serve directory --host 0.0.0.0 /data

Two problems with this one-line approach:

  • If you restart the server, all the indexing work is re-done from scratch.

  • If you horizontally scale with multiple containers, each one will crawl the filesystem individually, putting load on the filesystem and potentially getting views of the filesystem that are out of sync.

Read on for a scalable approach.

Scalable to Multiple Processes

Create a place outside the container to store the “catalog”, catalog.db.

mkdir storage/

Start the server, potentially multiple on different ports.

docker run \
  -p 8000:8000 \
  -e TILED_SINGLE_USER_API_KEY=secret \
  -v ./data:/data:ro \
  -v ./storage:/storage \
  ghcr.io/bluesky/tiled:latest

Register the files in the directory data/ with the catalog.

docker run \
  -e TILED_SINGLE_USER_API_KEY=secret \
  -v ./data:/data:ro \
  ghcr.io/bluesky/tiled:latest \
  tiled register http://localhost:8000/ /data --verbose

Scalable to Multiple Hosts

We will use one container to run a database server, and additional containers to run tiled services. To connect these services we create a bridge network.

docker network create -d bridge tilednet

Note

We chose to use a custom bridge network here for two reasons:

  1. The host network is not supported for Docker Desktop for Mac/Windows

  2. The default bridge network does not resolve container DNS entries by hostname

Instead of the default SQLite database, we need to use a PostgreSQL database. One way to run a PostgresSQL database is:

export TILED_DATABASE_PASSWORD=db_secret
mkdir postgres-data
docker run -d \
  --name tiled-test-postgres \
  --net=tilednet \
  -p 5432:5432 \
  -e POSTGRES_PASSWORD=${TILED_DATABASE_PASSWORD} \
  -v ./postgres-data:/var/lib/postgresql/data \
  docker.io/postgres:16

Initialize the database. (This creates the tables, indexes, and so on used by Tiled.)

export TILED_DATABASE_URI=postgresql+asyncpg://postgres:${TILED_DATABASE_PASSWORD}@tiled-test-postgres:5432

docker run --net=tilednet ghcr.io/bluesky/tiled:latest tiled catalog init $TILED_DATABASE_URI

Create a directory for Tiled configuration, e.g. config/.

mkdir config/

Place a copy of example_configs/single_catalog_single_user.yml, from the Tiled repository root, in this config/ directory.

Replace the line:

uri: "sqlite+aiosqlite:////storage/catalog.db"

with a PostgreSQL database URI, such as:

uri: "postgresql+asyncpg://postgres:${TILED_DATABASE_PASSWORD}@tiled-test-postgres:5432"

Start the server, potentially multiple servers across many hosts.

docker run \
  --net=tilednet \
  -p 8000:8000 \
  -e TILED_SINGLE_USER_API_KEY=secret \
  -e TILED_DATABASE_PASSWORD=${TILED_DATABASE_PASSWORD} \
  -v ./config:/deploy/config:ro \
  -v ./data:/data:ro \
  ghcr.io/bluesky/tiled:latest

Register the files in the directory data/ with this catalog.

docker run \
  --net=tilednet \
  -e TILED_SINGLE_USER_API_KEY=secret \
  -v ./data:/data:ro \
  ghcr.io/bluesky/tiled:latest \
  tiled register http://localhost:8000/ /data --verbose

Example: Custom configuration

There are configuration examples located in the directory example_configs under the Tiled repository root. The container image has one in particular, single_user_single_catalog.yml, copied into the container under /deploy/config/. Override it by mounting a local directory an /deploy/config as shown:

docker run \
  -p 8000:8000 \
  -e TILED_SINGLE_USER_API_KEY=secret \
  -v ./config:/deploy/config:ro \
  ghcr.io/bluesky/tiled:latest

You may need to mount additional volumes as well.

Example: Run Tiled with a dashboard of metrics

See Prometheus Metrics.

Next Steps

See Security and Access Control for examples addressing authentication and authorization.

See Service Configuration Reference for a comprehensive reference.