this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

update compose for nix

+243
+108
care/CLAUDE.md
··· 497 497 command: | 498 498 go build -o spindle.out ./cmd/spindle 499 499 ``` 500 + 501 + --- 502 + 503 + ## Docker Compose Setup 504 + 505 + ### Existing Compose Files 506 + 507 + The project has four compose files at the repository root: 508 + 509 + | File | Purpose | 510 + |---|---| 511 + | `docker-compose.yaml` | Infrastructure only (db, redis, minio) — used as a base for all modes | 512 + | `docker-compose.pre-built.yaml` | Runs pre-built GHCR image (`ghcr.io/ohcnetwork/care:latest`) — backend, celery-worker, celery-beat | 513 + | `docker-compose.local.yaml` | Local dev with source-mounted volumes and `dev.Dockerfile` | 514 + | `docker-compose.coolify.yaml` | Coolify PaaS deployment (similar to local but with coolify networking) | 515 + 516 + **Usage pattern:** `docker compose -f docker-compose.yaml -f docker-compose.pre-built.yaml up` 517 + 518 + The base `docker-compose.yaml` defines: 519 + - `db` — `postgres:alpine` on port 5433 (host) → 5432 (container), healthcheck via `pg_isready` 520 + - `redis` — `redis:8-alpine` on port 6380 (host) → 6379 (container), healthcheck via `redis-cli ping` 521 + - `minio` — `minio/minio:latest` on ports 9100 (S3 API) and 9001 (console), with init scripts at `docker/minio/` 522 + - Volumes: `postgres-data`, `redis-data` 523 + - Network: `care` (named default network) 524 + 525 + The pre-built overlay (`docker-compose.pre-built.yaml`) defines: 526 + - `backend` — image `ghcr.io/ohcnetwork/care:latest`, entrypoint `bash start.sh`, port 9000 527 + - `celery-worker` — same image, entrypoint `bash celery_worker.sh` 528 + - `celery-beat` — same image, entrypoint `bash celery_beat.sh`, healthcheck determines readiness for backend/worker 529 + 530 + All services use `./docker/.prebuilt.env` for environment configuration. 531 + 532 + ### Env Files 533 + 534 + | File | Purpose | 535 + |---|---| 536 + | `docker/.prebuilt.env` | Production-like env: `DJANGO_SETTINGS_MODULE=config.settings.deployment`, `DJANGO_DEBUG=False`, full DB/Redis/MinIO/S3 config | 537 + | `docker/.local.env` | Dev env: `DJANGO_DEBUG=true`, `ATTACH_DEBUGGER=false`, subset of config vars | 538 + 539 + ### Nix Image vs Dockerfile Image — Script Path Compatibility 540 + 541 + **Critical difference:** The prod Dockerfile and the Nix image place entrypoint scripts at different paths. 542 + 543 + **Prod Dockerfile (`docker/prod.Dockerfile`):** 544 + 1. `COPY --chmod=0755 --chown=django:django ./scripts/*.sh $APP_HOME` — copies all `.sh` files **flat** into `/app/` (e.g., `/app/start.sh`, `/app/wait_for_db.sh`) 545 + 2. `COPY --chown=django:django . $APP_HOME` — copies the full source tree to `/app/` (so scripts also exist at `/app/scripts/start.sh`) 546 + 547 + Result: Scripts exist at **both** `/app/start.sh` and `/app/scripts/start.sh`. The entrypoint `bash start.sh` works because WORKDIR is `/app`, and `start.sh` internally calls `./wait_for_db.sh` which resolves to `/app/wait_for_db.sh`. 548 + 549 + **Nix image (`nix/docker-image.nix`) — BEFORE fix:** 550 + 1. `rsync` copies the entire source tree to `/app/` — scripts land at `/app/scripts/start.sh` 551 + 2. There was **no flat copy** of scripts to `/app/` root 552 + 3. The healthcheck is configured as `/app/scripts/healthcheck.sh` (absolute path, correct) 553 + 554 + Without the fix, scripts existed **only** at `/app/scripts/start.sh`. The entrypoint `bash start.sh` would **fail** because `/app/start.sh` did not exist. 555 + 556 + **Additionally**, the scripts themselves use relative paths internally: 557 + - `start.sh` calls `./wait_for_db.sh` and `./wait_for_redis.sh` 558 + - `celery_worker.sh` calls `./wait_for_db.sh` and `./wait_for_redis.sh` 559 + - `celery_beat.sh` calls `./wait_for_db.sh` and `./wait_for_redis.sh` 560 + 561 + These resolve relative to WORKDIR (`/app`), so they need the flat copies to exist. 562 + 563 + **Fix applied to `nix/docker-image.nix`:** Added a step in the `appDir` derivation that copies `scripts/*.sh` flat into `/app/` root, mirroring the prod Dockerfile's `COPY --chmod=0755 ./scripts/*.sh $APP_HOME`. The existing `chmod +x` loop for top-level `*.sh` files then makes them executable. This maintains full backward compatibility — the same `bash start.sh` entrypoint used by the GHCR pre-built compose works identically with the Nix image. 564 + 565 + ```nix 566 + # Copy scripts/*.sh flat into /app/ root 567 + if [ -d "$out/app/scripts" ]; then 568 + for f in $out/app/scripts/*.sh; do 569 + [ -f "$f" ] && cp "$f" "$out/app/$(basename "$f")" 570 + done 571 + fi 572 + ``` 573 + 574 + ### Nix Image — Additional Env Var Differences 575 + 576 + The Nix image sets several env vars that point to Nix store paths (TLS certs, fontconfig). These are baked into the image config and do not need to be provided via the env file. Key ones: 577 + - `SSL_CERT_FILE`, `NIX_SSL_CERT_FILE`, `CURL_CA_BUNDLE`, `REQUESTS_CA_BUNDLE` — point to `${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt` 578 + - `FONTCONFIG_PATH` — points to `${pkgs.fontconfig.out}/etc/fonts` 579 + - `PATH` — `/app/.venv/bin:/bin:/usr/bin:/sbin:/usr/sbin` (Nix store bins are symlinked into `/bin` by `buildLayeredImage`) 580 + 581 + The existing `.prebuilt.env` is compatible — it sets app-level config (DB, Redis, S3, Django settings) that the Nix image needs identically. 582 + 583 + ### Nix Image User 584 + 585 + The Nix image runs as `django` (UID 1000, GID 1000), same as the prod Dockerfile. The `fakeRootCommands` in the Nix expression create `/tmp/container-role` with mode 666, so the healthcheck script's `printf "api" > /tmp/container-role` works. However, `/tmp` persistence between container restarts depends on Docker's default tmpfs behavior — this should be fine since container-role is written at startup. 586 + 587 + ### Docker Compose for Nix-Built Image (`docker/docker-compose.nix-prebuilt.yaml`) — CREATED 588 + 589 + A self-contained compose file for running CARE with the Nix-built image. Unlike the existing split (`docker-compose.yaml` + `docker-compose.pre-built.yaml`), this single file includes all services (backend, celery, db, redis, minio) so it can be run standalone. 590 + 591 + **Usage:** 592 + ```bash 593 + # Default (uses docker.io/ohcnetwork/care:latest) 594 + docker compose -f docker/docker-compose.nix-prebuilt.yaml up 595 + 596 + # Specific tag 597 + CARE_IMAGE=docker.io/ohcnetwork/care:v25.28.0 docker compose -f docker/docker-compose.nix-prebuilt.yaml up 598 + ``` 599 + 600 + **Key design decisions:** 601 + - **Image reference:** `${CARE_IMAGE:-docker.io/ohcnetwork/care:latest}` — defaults to Docker Hub (where the Tangled build pushes), overridable via env var 602 + - **Entrypoints:** `bash start.sh`, `bash celery_worker.sh`, `bash celery_beat.sh` — identical to the GHCR pre-built compose (works because of the flat script copy fix in `nix/docker-image.nix`) 603 + - **Env file:** Uses same `docker/.prebuilt.env` — fully compatible, no changes needed 604 + - **Dependency graph:** celery-beat depends on db+redis (`service_started`); backend and celery-worker depend on db+redis (`service_started`) AND celery-beat (`service_healthy`). celery-beat runs migrations and creates `/tmp/healthy` marker for its healthcheck 605 + - **Volume paths:** Relative to `docker/` directory (where the compose file lives), so minio scripts reference `./minio/init-script.sh` and backups default to `../care-backups` 606 + - **Network:** Named `care` network shared by all services 607 + - **Ports:** Same as existing setup — 9000 (backend), 5433→5432 (postgres), 6380→6379 (redis), 9100→9000 (minio S3), 9001 (minio console)
+124
docker/docker-compose.nix-prebuilt.yaml
··· 1 + # Docker Compose for Nix-built CARE image 2 + # 3 + # This is a self-contained compose file for running the CARE application 4 + # using the Nix-built OCI image produced by nix/docker-image.nix and 5 + # pushed via .tangled/workflows/build.yml. 6 + # 7 + # Usage: 8 + # docker compose -f docker/docker-compose.nix-prebuilt.yaml up 9 + # 10 + # To use a specific image tag: 11 + # CARE_IMAGE=docker.io/tellmey/care:v25.28.0 docker compose -f docker/docker-compose.nix-prebuilt.yaml up 12 + # 13 + # The Nix image is functionally equivalent to the prod Dockerfile image 14 + # (docker/prod.Dockerfile) but built with Nix dockerTools.buildLayeredImage. 15 + # Key differences: 16 + # - TLS certs, fontconfig, and runtime libs come from the Nix store 17 + # (baked into the image ENV — no host-level config needed) 18 + # - The image runs as user "django" (UID 1000) by default 19 + # - Scripts exist at both /app/scripts/*.sh and /app/*.sh (flat copy) 20 + # so entrypoints like "bash start.sh" work identically to the GHCR image 21 + 22 + services: 23 + backend: 24 + image: "${CARE_IMAGE:-docker.io/tellmey/care:latest}" 25 + env_file: 26 + - ./.prebuilt.env 27 + entrypoint: ["bash", "start.sh"] 28 + restart: unless-stopped 29 + depends_on: 30 + db: 31 + condition: service_started 32 + redis: 33 + condition: service_started 34 + celery-beat: 35 + condition: service_healthy 36 + ports: 37 + - "9000:9000" 38 + 39 + celery-worker: 40 + image: "${CARE_IMAGE:-docker.io/tellmey/care:latest}" 41 + env_file: 42 + - ./.prebuilt.env 43 + entrypoint: ["bash", "celery_worker.sh"] 44 + restart: unless-stopped 45 + depends_on: 46 + db: 47 + condition: service_started 48 + redis: 49 + condition: service_started 50 + celery-beat: 51 + condition: service_healthy 52 + 53 + celery-beat: 54 + image: "${CARE_IMAGE:-docker.io/tellmey/care:latest}" 55 + env_file: 56 + - ./.prebuilt.env 57 + entrypoint: ["bash", "celery_beat.sh"] 58 + restart: unless-stopped 59 + depends_on: 60 + db: 61 + condition: service_started 62 + redis: 63 + condition: service_started 64 + 65 + db: 66 + image: postgres:alpine 67 + restart: unless-stopped 68 + env_file: 69 + - ./.prebuilt.env 70 + volumes: 71 + - postgres-data:/var/lib/postgresql/data 72 + - ${BACKUP_DIR:-../care-backups}:/backups 73 + ports: 74 + - "5433:5432" 75 + healthcheck: 76 + test: ["CMD", "pg_isready", "-U", "${POSTGRES_USER:-postgres}"] 77 + interval: 10s 78 + retries: 5 79 + start_period: 10s 80 + timeout: 10s 81 + 82 + redis: 83 + image: redis:8-alpine 84 + restart: unless-stopped 85 + volumes: 86 + - redis-data:/data 87 + ports: 88 + - "6380:6379" 89 + healthcheck: 90 + test: ["CMD", "redis-cli", "ping"] 91 + interval: 10s 92 + retries: 5 93 + start_period: 10s 94 + timeout: 10s 95 + 96 + minio: 97 + image: minio/minio:latest 98 + restart: unless-stopped 99 + environment: 100 + MINIO_ROOT_USER: ${MINIO_ACCESS_KEY:-minioadmin} 101 + MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY:-minioadmin} 102 + AWS_DEFAULT_REGION: ap-south-1 103 + volumes: 104 + - "../care/media/minio:/data" 105 + - "./minio/init-script.sh:/init-script.sh:ro" 106 + - "./minio/entrypoint.sh:/entrypoint.sh:ro" 107 + ports: 108 + - "9100:9000" 109 + - "9001:9001" 110 + entrypoint: ["/entrypoint.sh"] 111 + healthcheck: 112 + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/ready"] 113 + interval: 10s 114 + retries: 5 115 + start_period: 10s 116 + timeout: 10s 117 + 118 + volumes: 119 + postgres-data: 120 + redis-data: 121 + 122 + networks: 123 + default: 124 + name: care
+11
nix/docker-image.nix
··· 109 109 chmod -R +x $out/app/scripts/ 110 110 fi 111 111 112 + # Copy scripts/*.sh flat into /app/ root — mirrors the prod Dockerfile's 113 + # COPY --chmod=0755 --chown=django:django ./scripts/*.sh $APP_HOME 114 + # which places them at /app/start.sh, /app/wait_for_db.sh, etc. 115 + # The entrypoint scripts use relative calls (./wait_for_db.sh) that 116 + # resolve against WORKDIR (/app), so the flat copies must exist. 117 + if [ -d "$out/app/scripts" ]; then 118 + for f in $out/app/scripts/*.sh; do 119 + [ -f "$f" ] && cp "$f" "$out/app/$(basename "$f")" 120 + done 121 + fi 122 + 112 123 # Make top-level shell scripts executable (healthcheck.sh etc. are 113 124 # copied to /app in the Dockerfile) 114 125 for f in $out/app/*.sh; do