Local Demo Server
This guide walks you through running a local demo of the clustered Euro-Office Document Server using k3d (Kubernetes in Docker). It’s intended for development and testing, not production.
Prerequisites
You need Docker, k3d, kubectl, and Helm installed.
Docker
# Ubuntu 24.04
sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu noble stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER
newgrp docker
k3d, kubectl, Helm
# k3d
curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash
# kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
rm kubectl
# Helm
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh
rm get_helm.sh
Verify everything is installed:
docker --version && k3d version && kubectl version --client && helm version
Resource requirements
Docker Desktop / Colima needs at least 6 GB RAM and 4 CPUs allocated. The full stack (3 databases + docservice + converter + example + NFS) is not lightweight.
Build the images
This guide assumes you’ve already built the cluster images from https://github.com/Euro-Office/DocumentServer:
ghcr.io/euro-office/cluster-docs:latestghcr.io/euro-office/cluster-utils:latestghcr.io/euro-office/cluster-example:latest
Set up the cluster
# Shared directory mounted into all k3d nodes — this is how pods on different
# nodes get RWX storage without NFS in k3d
sudo mkdir -p /tmp/euro-office-shared/{ds-files,ds-runtime-config}
sudo chmod -R 777 /tmp/euro-office-shared
# Create the cluster
k3d cluster create euro-office \
--servers 1 --agents 2 \
--port "8080:80@loadbalancer" \
--k3s-arg "--disable=traefik@server:*" \
--volume "/tmp/euro-office-shared:/tmp/euro-office-shared@all"
# Namespace
kubectl create namespace euro-office
Load images into k3d
This avoids pushing to a remote registry during development. Repeat this step every time you rebuild:
k3d image import ghcr.io/euro-office/cluster-docs:latest -c euro-office
k3d image import ghcr.io/euro-office/cluster-utils:latest -c euro-office
k3d image import ghcr.io/euro-office/cluster-example:latest -c euro-office
Deploy dependencies
# Database, cache, message broker, shared storage
kubectl apply -f postgres.yaml
kubectl apply -f redis.yaml
kubectl apply -f rabbitmq.yaml
kubectl apply -f storage.yaml
# Wait for all four to be Running
kubectl get pods -n euro-office -w
Verify connectivity before installing the chart:
# Postgres
kubectl run pgtest --rm -it --restart=Never -n euro-office \
--image=postgres:16 -- \
psql "postgresql://onlyoffice:onlyoffice@pg-postgresql:5432/onlyoffice" -c "SELECT 1;"
# Redis
kubectl run redistest --rm -it --restart=Never -n euro-office \
--image=redis:7-alpine -- \
redis-cli -h redis-master -a redis ping
Postgres should print 1, Redis should print PONG.
Install the chart
helm install docs .. -n euro-office -f my-values.yml --timeout 10m
# Watch the install hooks run, then the deployments come up
kubectl get pods -n euro-office -w
Expected sequence:
wopi-keys-gen-*→ Completedpre-install-*→ Completedconverter-*→ 1/1 Runningdocservice-*→ 2/2 Running (docservice + proxy sidecar)example-0→ 1/1 Runningadminpanel-0→ 1/1 Running
Press Ctrl-C once everything reads Running or Completed.
Access the demo
kubectl port-forward -n euro-office svc/documentserver 8082:8888
Open http://localhost:8082 in a browser. The welcome page should load. Click into /example/ to access the demo editor app where you can create and edit documents.
Quick health check:
curl http://localhost:8082/healthcheck
# returns: true
Updating after a rebuild
When you rebuild any of the images:
# Reimport the changed image
k3d image import ghcr.io/euro-office/cluster-docs:latest -c euro-office
# Restart the affected workloads to pick up the new image
kubectl rollout restart deployment/docservice deployment/converter -n euro-office
# For the example app (StatefulSet):
kubectl delete pod example-0 -n euro-office
Common debugging
# What's not Ready?
kubectl get pods -n euro-office
# Why is a pod pending/crashing?
kubectl describe pod <pod-name> -n euro-office | tail -20
# Container logs
kubectl logs <pod-name> -n euro-office -c <container-name> --tail=100
kubectl logs -n euro-office -l app=docservice --tail=100 # by label
# Render chart manifests without installing (sanity-check overrides)
helm template docs .. -n euro-office -f my-values.yml | less
# Reset everything quickly during dev (much faster than helm uninstall)
k3d cluster delete euro-office
Tear down
Clean uninstall of just the application (keeps DBs, NFS, etc.):
helm uninstall docs -n euro-office --no-hooks
kubectl delete jobs -n euro-office --all
Full teardown (recommended for dev — leaves a clean slate):
k3d cluster delete euro-office
sudo rm -rf /tmp/euro-office-shared
Files in this directory
postgres.yaml— Postgres deployment, service, and secretredis.yaml— Redis deployment, service, and secretrabbitmq.yaml— RabbitMQ deployment, service, and secretstorage.yaml—nfsStorageClass and static PVs backed by the host-mounted shared directorymy-values.yml— Helm chart overrides (image references, connection URLs, JWT secret, env vars)
Limitations
This setup is for local testing only:
- All passwords (
onlyoffice,redis,rabbit, JWT secret) are dev placeholders — never use them in production - The shared host volume at
/tmp/euro-office-sharedonly works because k3d nodes run on a single host; in a real cluster, replacestorage.yamlwith proper NFS or another RWX provisioner - Single-replica databases with no backups
- No TLS, no ingress, port-forwarding only