All checks were successful
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 33s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 1m10s
Build and Push Docker Images / Build Integrator (push) Successful in 57s
Build and Push Docker Images / Build Kestra Init (push) Successful in 32s
Build and Push Docker Images / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 32s
Build and Push Docker Images / Trigger Portainer Update (push) Successful in 1s
The named volume was shadowing the DAGs built into the pipeline image with an empty directory. DAGs now served directly from the image and update on each CI build. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
168 lines
4.6 KiB
YAML
168 lines
4.6 KiB
YAML
version: '3.8'
|
|
|
|
services:
|
|
# PostgreSQL Database with PostGIS
|
|
db:
|
|
image: postgis/postgis:16-3.4-alpine
|
|
container_name: schoolcompare_db
|
|
environment:
|
|
POSTGRES_USER: schoolcompare
|
|
POSTGRES_PASSWORD: schoolcompare
|
|
POSTGRES_DB: schoolcompare
|
|
volumes:
|
|
- postgres_data:/var/lib/postgresql/data
|
|
ports:
|
|
- "5432:5432"
|
|
networks:
|
|
- schoolcompare-network
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U schoolcompare"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 10s
|
|
|
|
# FastAPI Backend
|
|
backend:
|
|
image: privaterepo.sitaru.org/tudor/school_compare-backend:latest
|
|
container_name: schoolcompare_backend
|
|
ports:
|
|
- "8000:80"
|
|
environment:
|
|
DATABASE_URL: postgresql://schoolcompare:schoolcompare@db:5432/schoolcompare
|
|
PYTHONUNBUFFERED: 1
|
|
ADMIN_API_KEY: ${ADMIN_API_KEY:-changeme}
|
|
TYPESENSE_URL: http://typesense:8108
|
|
TYPESENSE_API_KEY: ${TYPESENSE_API_KEY:-changeme}
|
|
volumes:
|
|
- ./data:/app/data:ro
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
networks:
|
|
- schoolcompare-network
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:80/api/data-info"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 30s
|
|
|
|
# Next.js Frontend
|
|
nextjs:
|
|
image: privaterepo.sitaru.org/tudor/school_compare-frontend:latest
|
|
container_name: schoolcompare_nextjs
|
|
ports:
|
|
- "3000:3000"
|
|
environment:
|
|
NODE_ENV: production
|
|
NEXT_PUBLIC_API_URL: http://localhost:8000/api
|
|
FASTAPI_URL: http://backend:80/api
|
|
TYPESENSE_URL: http://typesense:8108
|
|
TYPESENSE_API_KEY: ${TYPESENSE_SEARCH_KEY:-changeme}
|
|
depends_on:
|
|
backend:
|
|
condition: service_healthy
|
|
networks:
|
|
- schoolcompare-network
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 40s
|
|
|
|
# Typesense — search engine
|
|
typesense:
|
|
image: typesense/typesense:30.1
|
|
container_name: schoolcompare_typesense
|
|
ports:
|
|
- "8108:8108"
|
|
environment:
|
|
TYPESENSE_API_KEY: ${TYPESENSE_API_KEY:-changeme}
|
|
TYPESENSE_DATA_DIR: /data
|
|
volumes:
|
|
- typesense_data:/data
|
|
networks:
|
|
- schoolcompare-network
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "cat < /dev/tcp/localhost/8108"]
|
|
interval: 15s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 10s
|
|
|
|
# Apache Airflow — API server + UI (http://localhost:8080)
|
|
airflow-api-server:
|
|
image: privaterepo.sitaru.org/tudor/school_compare-pipeline:latest
|
|
container_name: schoolcompare_airflow_api
|
|
command: airflow api-server --port 8080
|
|
ports:
|
|
- "8080:8080"
|
|
environment: &airflow-env
|
|
AIRFLOW__CORE__EXECUTOR: LocalExecutor
|
|
AIRFLOW__DATABASE__SQL_ALCHEMY_CONN: postgresql+psycopg2://schoolcompare:schoolcompare@db:5432/schoolcompare
|
|
AIRFLOW__CORE__DAGS_FOLDER: /opt/pipeline/dags
|
|
AIRFLOW__CORE__LOAD_EXAMPLES: "false"
|
|
AIRFLOW__CORE__SIMPLE_AUTH_MANAGER_USERS: "admin:admin"
|
|
PG_HOST: db
|
|
PG_PORT: "5432"
|
|
PG_USER: schoolcompare
|
|
PG_PASSWORD: schoolcompare
|
|
PG_DATABASE: schoolcompare
|
|
TYPESENSE_URL: http://typesense:8108
|
|
TYPESENSE_API_KEY: ${TYPESENSE_API_KEY:-changeme}
|
|
volumes:
|
|
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
networks:
|
|
- schoolcompare-network
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:8080/api/v2/monitor/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 5
|
|
start_period: 60s
|
|
|
|
airflow-scheduler:
|
|
image: privaterepo.sitaru.org/tudor/school_compare-pipeline:latest
|
|
container_name: schoolcompare_airflow_scheduler
|
|
command: airflow scheduler
|
|
environment: *airflow-env
|
|
volumes:
|
|
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
networks:
|
|
- schoolcompare-network
|
|
restart: unless-stopped
|
|
|
|
# One-shot: initialise Airflow metadata DB
|
|
airflow-init:
|
|
image: privaterepo.sitaru.org/tudor/school_compare-pipeline:latest
|
|
container_name: schoolcompare_airflow_init
|
|
command: airflow db migrate
|
|
environment: *airflow-env
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
networks:
|
|
- schoolcompare-network
|
|
restart: "no"
|
|
|
|
networks:
|
|
schoolcompare-network:
|
|
driver: bridge
|
|
|
|
volumes:
|
|
postgres_data:
|
|
typesense_data:
|