diff --git a/README.md b/README.md index 7052a31..e25ad64 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,53 @@ docker pull ghcr.io/gipplab/qlever-control:latest docker-compose down ``` +### Using Docker Stack (Docker Swarm) + +For production deployments using Docker Swarm, use the provided `docker-stack.yml` template: + +1. Initialize Docker Swarm (if not already initialized): + ```bash + docker swarm init + ``` + +2. Deploy the stack: + ```bash + docker stack deploy -c docker-stack.yml qlever + ``` + +3. Check the service status: + ```bash + docker stack services qlever + docker service ps qlever_qlever-control + ``` + +4. Access the container: + ```bash + # Get the container ID/name + docker service ps qlever_qlever-control --filter desired-state=running --format '{{.Name}}.{{.ID}}' + + # Access the container (replace CONTAINER_ID with actual ID from above) + docker exec -it qlever_qlever-control.1.CONTAINER_ID bash + ``` + + Or use this one-liner (if only one container is running): + ```bash + docker exec -it $(docker ps -q -f name=qlever_qlever-control) bash + ``` + +5. Remove the stack: + ```bash + docker stack rm qlever + ``` + +The `docker-stack.yml` template uses the latest pre-built image from GitHub Container Registry (`ghcr.io/gipplab/qlever-control:latest`) and includes: +- Resource limits and reservations +- Restart policies +- Update and rollback configurations +- Persistent volume for workspace data + +**Note:** The service runs with `replicas: 1` because the Docker socket mount prevents horizontal scaling. See the Security Note section below for important security considerations when mounting the Docker socket. + ### Using Docker directly 1. Build the image: diff --git a/docker-stack.yml b/docker-stack.yml new file mode 100644 index 0000000..5c5ec39 --- /dev/null +++ b/docker-stack.yml @@ -0,0 +1,83 @@ +# Docker Stack deployment template for QLever Control +# This file is designed for use with Docker Swarm +# +# Deploy the stack: +# docker stack deploy -c docker-stack.yml qlever +# +# Remove the stack: +# docker stack rm qlever +# +# List services: +# docker stack services qlever + +version: "3.8" + +services: + qlever-control: + # Use the latest image from GitHub Container Registry + image: ghcr.io/gipplab/qlever-control:latest + + volumes: + # Mount Docker socket to allow running Docker commands on host + # SECURITY WARNING: Mounting the Docker socket gives this container full control over + # the Docker daemon, equivalent to root access on the host. Only use in trusted environments. + # Note: In swarm mode, this will use the socket from the node where the container runs. + # This also limits horizontal scaling - the service must run with replicas: 1 + - /var/run/docker.sock:/var/run/docker.sock + # Mount workspace directory for working with files + - qlever-workspace:/workspace + + environment: + # Set to "true" to test Docker connectivity on startup + - TEST_DOCKER=false + + # Keep container running with stdin and tty + stdin_open: true + tty: true + + # Deployment configuration for Docker Swarm + deploy: + # Run one replica of the service + # Note: Must be 1 due to Docker socket mount - cannot scale horizontally + replicas: 1 + + # Restart policy + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 3 + window: 120s + + # Resource limits and reservations + resources: + limits: + cpus: '2.0' + memory: 2G + reservations: + cpus: '0.5' + memory: 512M + + # Placement constraints (optional) + # Uncomment to run on manager nodes only + # placement: + # constraints: + # - node.role == manager + + # Update configuration + update_config: + parallelism: 1 + delay: 10s + failure_action: rollback + order: stop-first + + # Rollback configuration + rollback_config: + parallelism: 1 + delay: 10s + failure_action: pause + order: stop-first + +# Named volume for persistent workspace data across container restarts +volumes: + qlever-workspace: + driver: local