All checks were successful
Deploy storage stack / deploy (push) Successful in 20s
Garage serves all three buckets and both apps, and a last comparison found nothing in MinIO that Garage lacks. Drop the MinIO service, its bootstrap and its root credentials from the deploy, and let compose remove the leftover containers. The storage_minio_data volume is left on the host. All images can be pulled again, so the deploy goes back to failing on a pull error. Document Garage in the README and SECRETS, including the key format and how the existing secrets map to it, and swap the MinIO client in the flake for awscli and rclone. Assisted-by: Claude:fable-5-2
90 lines
3.1 KiB
YAML
90 lines
3.1 KiB
YAML
services:
|
|
postgres:
|
|
image: postgres:17-alpine
|
|
container_name: storage-postgres
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_USER: postgres
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
|
POSTGRES_DB: postgres
|
|
volumes:
|
|
- pg_data:/var/lib/postgresql/data
|
|
networks:
|
|
- storage
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 10
|
|
|
|
postgres-init:
|
|
image: postgres:17-alpine
|
|
container_name: storage-postgres-init
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
environment:
|
|
PGHOST: postgres
|
|
PGUSER: postgres
|
|
PGPASSWORD: ${POSTGRES_PASSWORD}
|
|
ASXPIO_DB_PASSWORD: ${ASXPIO_DB_PASSWORD}
|
|
BINGO_DB_PASSWORD: ${BINGO_DB_PASSWORD}
|
|
volumes:
|
|
- ./init/postgres-init.sh:/init.sh:ro
|
|
entrypoint: ["/bin/sh", "/init.sh"]
|
|
networks:
|
|
- storage
|
|
restart: "no"
|
|
|
|
garage:
|
|
image: dxflrs/garage:v2.5.0
|
|
container_name: storage-garage
|
|
restart: unless-stopped
|
|
command: ["/garage", "server", "--single-node"]
|
|
volumes:
|
|
- ./garage.toml:/etc/garage.toml:ro
|
|
- ./secrets/garage_rpc_secret:/run/secrets/garage_rpc_secret:ro
|
|
- garage_meta:/var/lib/garage/meta
|
|
- garage_data:/var/lib/garage/data
|
|
networks:
|
|
- storage
|
|
- traefik
|
|
healthcheck:
|
|
test: ["CMD", "/garage", "status"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 10
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.docker.network=traefik"
|
|
# The S3 API.
|
|
- "traefik.http.routers.garage-s3.rule=Host(`s3.asxp.io`)"
|
|
- "traefik.http.routers.garage-s3.entrypoints=websecure"
|
|
- "traefik.http.routers.garage-s3.tls=true"
|
|
- "traefik.http.routers.garage-s3.tls.certresolver=letsencrypt"
|
|
- "traefik.http.routers.garage-s3.service=garage-s3"
|
|
- "traefik.http.services.garage-s3.loadbalancer.server.port=3900"
|
|
# Anonymous reads of the public bucket: unsigned GET/HEAD of
|
|
# /public/<key> goes to the web endpoint as Host public.web.garage,
|
|
# path /<key>. Signed requests still reach the S3 API above.
|
|
- "traefik.http.routers.garage-public.rule=Host(`s3.asxp.io`) && PathPrefix(`/public/`) && (Method(`GET`) || Method(`HEAD`)) && !HeaderRegexp(`Authorization`, `.+`) && !QueryRegexp(`X-Amz-Signature`, `.+`)"
|
|
- "traefik.http.routers.garage-public.priority=1000"
|
|
- "traefik.http.routers.garage-public.entrypoints=websecure"
|
|
- "traefik.http.routers.garage-public.tls=true"
|
|
- "traefik.http.routers.garage-public.tls.certresolver=letsencrypt"
|
|
- "traefik.http.routers.garage-public.service=garage-web"
|
|
- "traefik.http.routers.garage-public.middlewares=garage-public-strip,garage-public-host"
|
|
- "traefik.http.middlewares.garage-public-strip.stripprefix.prefixes=/public"
|
|
- "traefik.http.middlewares.garage-public-host.headers.customrequestheaders.Host=public.web.garage"
|
|
- "traefik.http.services.garage-web.loadbalancer.server.port=3902"
|
|
|
|
volumes:
|
|
pg_data:
|
|
garage_meta:
|
|
garage_data:
|
|
|
|
networks:
|
|
storage:
|
|
name: storage
|
|
traefik:
|
|
external: true
|