Example: a database
Postgres with a named volume, a password from vars set, and a web UI.
Postgres keeps its data in a named volume, which lasts across deploys. Its
password comes from an environment variable, so it stays out of the
repository. Adminer, a web UI for databases, is
the only service routed to the internet; it reaches Postgres by its service
name, db, on the project's default network.
Files #
compose.yaml
1services:
2 adminer:
3 image: adminer
4 environment:
5 ADMINER_DEFAULT_SERVER: db
6 labels:
7 - traefik.enable=true
8 - traefik.docker.network=picd-ingress
9 - traefik.http.routers.adminer.rule=Host(`db-alice.user.cd.pico.sh`)
10 networks: [default, picd-ingress]
11 db:
12 image: postgres:17
13 environment:
14 POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set it with vars set}
15 volumes:
16 - data:/var/lib/postgresql/data
17volumes:
18 data:
19networks:
20 picd-ingress:
21 external: true
adminer is on both networks: picd-ingress for Traefik, and default to
reach db. traefik.docker.network tells Traefik which of them to use.
Deploy #
Set the password first, which creates the project, then push:
1ssh cd.pico.sh vars set db POSTGRES_PASSWORD="$(openssl rand -hex 16)"
2git init -b main && git add . && git commit -m init
3git push ssh://cd.pico.sh/db.git main
Sign in at https://db-alice.user.cd.pico.sh as postgres, with the
password. Adminer is open to anyone who knows it, so take the project down
when you're done:
1ssh cd.pico.sh down db
down keeps the volume, so the data is there when you redeploy.