Files

83 lines
2.7 KiB
Markdown

# Docker Swarm
**Last updated:** 2026-08-11
## Overview
Container orchestration uses Docker Swarm managed through Portainer. All
production services are deployed as Swarm stacks, not standalone containers.
## Topology
| Role | Hostname | IP |
|------|----------|----|
| Swarm manager | impulse-controller | 192.168.50.120 |
| Database node | memory-archives | 192.168.50.107 |
| Hypervisor | *(Xen Orchestra)* | 192.168.50.100 |
- **Portainer:** https://192.168.50.120:9443
- **Hypervisor:** Xen (Xen Orchestra UI at 192.168.50.100)
## Databases
All databases are centralised on `memory-archives` (192.168.50.107):
| Engine | Notes |
|--------|-------|
| PostgreSQL 16 + pgvector | Primary relational store; vector extension enabled |
| MySQL | Legacy / compatibility workloads |
Services should connect to `memory-archives` by hostname, not IP, where
Swarm DNS resolves within the overlay network.
## Stack YAML Conventions
```yaml
# No top-level 'version:' field — Swarm ignores it and modern Compose drops it
services:
myservice:
image: example/myservice:latest
restart: unless-stopped # required on all services
networks:
- master-proxy-overlay
deploy:
labels:
# Traefik labels go under deploy:, not at the service root
- "traefik.enable=true"
- "traefik.http.routers.myservice.rule=Host(`myservice.pldyn.net`)"
- "traefik.http.routers.myservice.entrypoints=websecure"
- "traefik.http.routers.myservice.tls.certresolver=cloudflare"
# HTTP → HTTPS redirect
- "traefik.http.routers.myservice-http.rule=Host(`myservice.pldyn.net`)"
- "traefik.http.routers.myservice-http.entrypoints=web"
- "traefik.http.routers.myservice-http.middlewares=redirect-to-https@docker"
networks:
master-proxy-overlay:
external: true
```
Key conventions:
- No `version:` field at the top of the file
- `restart: unless-stopped` on every service
- Traefik labels placed under `deploy:` (not at service root)
- HTTP→HTTPS redirect middleware included for every public-facing service
## Service Discovery
Swarm services are referenced by **service name**, not container name.
Container names are non-deterministic across replicas; service names are
stable within the overlay network.
## Sharp Edges
### Portainer env UI passes literal quotes
When setting environment variables via the Portainer UI, the value field
passes content verbatim — including any quotes you type. Do **not** wrap
values in `"..."` or `'...'` in the UI; the quotes become part of the value
and will break the application.
**Correct:** `MY_VAR=somevalue`
**Wrong:** `MY_VAR="somevalue"` ← the quotes are included in the string