perf(imagens): o ARG de versão vem depois das camadas caras

No BuildKit a instrução ARG entra na chave de cache de tudo o que vem depois,
e APP_VERSION muda a cada release. No worker ela vinha antes do pnpm install:
toda release reinstalava as dependências inteiras. No app (runner) e no
scheduler, antes do apk add. Agora declaração e uso descem para depois das
camadas caras, junto da cópia do artefato.

Medido com Docker real (Dockerfile.scheduler, cache limpo, duas versões):
main oficial → apk add DONE 1.2s nas duas; este commit → DONE e depois CACHED.
A imagem segue com APP_VERSION certo (conferido dentro do contêiner).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
bonito-system
2026-09-24 02:23:56 +00:00
co-authored by Claude Opus 5.5
parent 39ed2e2682
commit 61c4b46dd2
4 changed files with 34 additions and 12 deletions
@@ -0,0 +1,7 @@
---
impacto: nada_mudou
secao: alterado
titulo: A construção das imagens não reinstala as dependências só porque o número da versão mudou
---
As três imagens declaravam o número da versão antes das etapas mais demoradas da construção, e isso fazia o Docker refazer essas etapas em toda versão nova: no worker, a instalação inteira das dependências; no app e no scheduler, a instalação dos pacotes do sistema. Agora o número entra no fim, e essas etapas são reaproveitadas de uma versão para a outra. Nada muda no que a imagem contém nem no que quem opera precisa fazer. Crédito: @bonito-system.
+14 -7
View File
@@ -90,22 +90,29 @@ LABEL org.opencontainers.image.source="https://github.com/melgarafael/DeskcommCR
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.title="DeskcommCRM"
# A versão que /api/v1/health reporta (invariante 7). Precisa vir por ARG: a
# alternativa anterior era `process.env.npm_package_version`, que é `undefined`
# sob `CMD ["node","server.js"]` — só existe quando o processo nasce de um
# `npm`/`pnpm run`. Toda instalação do mundo reportava o fallback "0.1.0".
ARG APP_VERSION=dev
# ⚠️ NADA de ARG de versão acima das camadas caras deste estágio. No BuildKit a
# própria INSTRUÇÃO `ARG` entra na chave de cache das instruções seguintes —
# mesmo sem `ENV` no meio — e `APP_VERSION` muda a cada release. Medido
# (2026-09-13, três builds do mesmo fonte): versão nova → `apk add ffmpeg`
# REEXECUTA (23–41s); mesma versão → CACHED (3s). Por isso a declaração E o uso
# descem para depois do `apk add` e do `adduser`, junto da cópia do artefato.
ENV NODE_ENV=production \
PORT=3000 \
HOSTNAME=0.0.0.0 \
NEXT_TELEMETRY_DISABLED=1 \
APP_VERSION=$APP_VERSION
NEXT_TELEMETRY_DISABLED=1
# ffmpeg: a derivação de vídeo (Onda 3.1) roda no processo do app — o cron
# event-log-drain executa o media_derive handler, que chama `ffmpeg` via spawn
# pra extrair áudio+frames. Sem o binário, todo vídeo recebido falha a derivação.
RUN apk add --no-cache ffmpeg
# non-root
RUN addgroup -g 1001 -S nodejs && adduser -S nextjs -u 1001
# A versão que /api/v1/health reporta (invariante 7). Precisa vir por ARG: a
# alternativa anterior era `process.env.npm_package_version`, que é `undefined`
# sob `CMD ["node","server.js"]` — só existe quando o processo nasce de um
# `npm`/`pnpm run`. Toda instalação do mundo reportava o fallback "0.1.0".
# Declarada AQUI, depois das camadas caras (ver acima).
ARG APP_VERSION=dev
ENV APP_VERSION=$APP_VERSION
# O output standalone NÃO inclui public/ nem .next/static — copiar explicitamente,
# senão CSS/JS/assets retornam 404 (app "sem estilo").
COPY --from=build --chown=nextjs:nodejs /app/.next/standalone ./
+6 -3
View File
@@ -11,15 +11,18 @@ LABEL org.opencontainers.image.source="https://github.com/melgarafael/DeskcommCR
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.title="DeskcommCRM scheduler"
ARG APP_VERSION=dev
ENV APP_VERSION=$APP_VERSION \
TZ=UTC
ENV TZ=UTC
RUN apk add --no-cache curl tzdata
COPY docker/scheduler/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
# A versão depois das camadas que custam (o `apk add`): a instrução `ARG` entra
# na chave de cache de tudo o que vem depois, e ela muda a cada release.
ARG APP_VERSION=dev
ENV APP_VERSION=$APP_VERSION
# Prova de vida: se o crond morrer, o contêiner cai e o `restart: unless-stopped`
# o traz de volta. Sem isto, um crond morto fica indistinguível de um cron ocioso.
HEALTHCHECK --interval=60s --timeout=5s --start-period=10s --retries=3 \
+7 -2
View File
@@ -10,8 +10,6 @@ LABEL org.opencontainers.image.source="https://github.com/melgarafael/DeskcommCR
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.title="DeskcommCRM worker"
ARG APP_VERSION=dev
ENV APP_VERSION=$APP_VERSION
# pnpm fixado na versão do lockfile do repo (pnpm 10 bloquearia build scripts).
RUN corepack enable && corepack prepare pnpm@9.15.9 --activate
@@ -21,6 +19,13 @@ RUN pnpm install --frozen-lockfile
COPY . .
# A versão por ÚLTIMO. Declarada antes do `pnpm install`, como estava, a
# instrução `ARG` entrava na chave de cache de tudo o que vem depois e a
# instalação INTEIRA de dependências era refeita a cada release, só porque o
# número mudou. Aqui ela só invalida o que não custa nada.
ARG APP_VERSION=dev
ENV APP_VERSION=$APP_VERSION
# Healthz do worker (bind 0.0.0.0 dentro do container).
EXPOSE 8787