From f117e1e9d7579c5043ebc4938e53be17317257cd Mon Sep 17 00:00:00 2001 From: Lucas Rayan Date: Sun, 2 Aug 2026 14:25:24 -0300 Subject: [PATCH] #21: deploy by pulling the images CI built, not by rebuilding on the server The first deployments died building on the target: four images, and the webmail build alone was enough to sink it on a small arm64 host - the build step was killed with no BuildKit error, which is what an exhausted or overloaded machine looks like from the outside. The images already exist. CI publishes all four to GHCR for amd64 and arm64 on every merge, and they are the ones the suite ran against, so rebuilding them on the deploy target is slower, heavier and less trustworthy than pulling them. docker-compose.yaml therefore carries no build definitions, and docker-compose.build.yaml is the overlay that adds them for local development and for CI - which does have to exercise the branch rather than the published images. Both paths were run before committing. Co-Authored-By: Claude Opus 5 --- .github/workflows/ci.yml | 11 +++++------ Makefile | 3 ++- README.md | 2 +- docker-compose.build.yaml | 21 +++++++++++++++++++++ docker-compose.yaml | 4 ---- docs/DEPLOYMENT.md | 4 ++++ 6 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 docker-compose.build.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba2abcb..5a5d0eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -200,9 +200,8 @@ jobs: # start the stack at all. - name: Cria a rede do proxy run: docker network create "${COOLIFY_PROXY_NETWORK:-coolify}" - # --build makes compose build each service locally and tag it under the - # same name the published image uses, so the stack comes up without ever - # reaching the registry. - - run: docker compose --env-file .env up --build --wait - - run: docker compose ps - - run: docker compose down -v + # The build overlay is explicit here: CI has to exercise the code in the + # branch, not the images already published from main. + - run: docker compose -f docker-compose.yaml -f docker-compose.build.yaml --env-file .env up --build --wait + - run: docker compose -f docker-compose.yaml -f docker-compose.build.yaml ps + - run: docker compose -f docker-compose.yaml -f docker-compose.build.yaml down -v diff --git a/Makefile b/Makefile index fa0fd4d..0d5790c 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ .PHONY: up down logs test lint migrate-up migrate-down gen-dev-cert seed preflight create-admin reset-password +# Local development builds from source; production pulls what CI published. up: - docker compose --env-file .env up --build + docker compose -f docker-compose.yaml -f docker-compose.build.yaml --env-file .env up --build down: docker compose down -v diff --git a/README.md b/README.md index 3357d97..e42ce48 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ route into the console needs one. ```bash cp .env.example .env make gen-dev-cert # self-signed certificate for the listeners -docker compose up --build +make up # builds from source via the build overlay make seed # a postmaster@example.test fixture ``` diff --git a/docker-compose.build.yaml b/docker-compose.build.yaml new file mode 100644 index 0000000..8e5bacc --- /dev/null +++ b/docker-compose.build.yaml @@ -0,0 +1,21 @@ +# Development overlay: builds the images from source instead of pulling them. +# +# Production deploys pull what CI already built and tested, so the compose file +# proper carries no build definitions - rebuilding four images on the target +# host is slow and, on a small server, the webmail build is enough to fail the +# deployment outright. +# +# Use it explicitly: +# docker compose -f docker-compose.yaml -f docker-compose.build.yaml up --build +services: + auth: + build: { context: ./services/auth } + + storage: + build: { context: ./services/storage } + + protocols: + build: { context: ./services/protocols } + + web: + build: { context: ./services/webmail } diff --git a/docker-compose.yaml b/docker-compose.yaml index 78cb1a9..999e3c8 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -122,7 +122,6 @@ services: # -------------------------------------------------------------- AUTH auth: image: ${IMAGE_NAMESPACE:-ghcr.io/lucasrguerra/lambdamail}/auth:${IMAGE_TAG:-latest} - build: { context: ./services/auth } restart: *restart logging: *default-logging environment: @@ -156,7 +155,6 @@ services: # ----------------------------------------------------------- STORAGE storage: image: ${IMAGE_NAMESPACE:-ghcr.io/lucasrguerra/lambdamail}/storage:${IMAGE_TAG:-latest} - build: { context: ./services/storage } restart: *restart logging: *default-logging environment: @@ -187,7 +185,6 @@ services: # --------------------------------------------------------- PROTOCOLS protocols: image: ${IMAGE_NAMESPACE:-ghcr.io/lucasrguerra/lambdamail}/protocols:${IMAGE_TAG:-latest} - build: { context: ./services/protocols } restart: *restart logging: *default-logging ports: @@ -266,7 +263,6 @@ services: # -------------------------------------------------------------- WEB web: image: ${IMAGE_NAMESPACE:-ghcr.io/lucasrguerra/lambdamail}/webmail:${IMAGE_TAG:-latest} - build: { context: ./services/webmail } restart: *restart logging: *default-logging environment: diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index 74423fc..4bd702e 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -177,6 +177,10 @@ docker compose pull docker compose up -d ``` +Deploys pull the images CI published rather than building on the server; +`docker-compose.build.yaml` is the overlay local development uses to build from +source instead. + Migrations run automatically on start, before the services that depend on them. To pin a version, set `IMAGE_TAG` to a release version or a `sha-` tag rather than `latest`.