Wiedii — Política de Contenedores Docker
⚠️ Verificar versiones antes de usar — los números de versión de imágenes base en esta nota pueden estar desactualizados. Usar
docker pull <image>y revisar las notas de lanzamiento oficiales antes de fijar versiones. Ver politicas-core.
Todo contenedor de producción en Wiedii sigue estas convenciones. El objetivo es: imágenes mínimas, reproducibles, seguras y multi-plataforma por defecto.
1. Estructura multi-stage obligatoria
Todo Dockerfile debe usar al menos dos stages:
| Stage | Imagen base | Propósito |
|---|---|---|
build | Runtime completo (oven/bun, golang, node) | Compilar artefactos |
| Runtime (sin nombre especial) | Imagen mínima (alpine, distroless) | Ejecutar únicamente el artefacto |
El stage de runtime nunca instala dependencias de construcción. Solo recibe los artefactos copiados desde build.
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM oven/bun:1.3.14-alpine AS build
WORKDIR /app
# ... instalar deps y compilar ...
FROM caddy:2.9.1-alpine
# ... copiar artefactos y configurar runtime ...
2. Primera línea obligatoria
# syntax=docker/dockerfile:1
Activa BuildKit y habilita las instrucciones avanzadas (--mount, --secret, --ssh). Sin esta línea, las instrucciones de caché y secretos no están disponibles.
3. Imágenes base — versiones exactas
# ❌ Prohibido
FROM node:alpine
FROM caddy:latest
# ✅ Requerido
FROM oven/bun:1.3.14-alpine
FROM caddy:2.9.1-alpine
Renovate gestiona las actualizaciones automáticamente si las versiones están fijadas. Con :latest o :alpine, Renovate no puede rastrear ni actualizar.
4. Multi-plataforma: BUILDPLATFORM y TARGETARCH
FROM --platform=$BUILDPLATFORM oven/bun:1.3.14-alpine AS build
--platform=$BUILDPLATFORMen el stage de build → usa la arquitectura de la máquina que construye (ej.linux/arm64en Mac con M-chip). Evita la emulación lenta.- El stage de runtime no lleva
--platformexplícito → Docker selecciona la arquitectura correcta según el target.
Para condicionamiento por arquitectura en el runtime:
ARG TARGETARCH
RUN if [ "$TARGETARCH" = "arm64" ]; then echo "ARM path"; fi
5. BuildKit cache mounts
Evita descargar dependencias en cada build:
# Bun / Node
RUN --mount=type=cache,target=/var/cache/bun \
bun install --frozen-lockfile
# Go
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
go build -o /app/bin ./...
# Python (uv)
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen
El cache mount persiste entre builds en la misma máquina. En CI, configurar el cache de BuildKit con --cache-from y --cache-to.
6. Usuario no-root obligatorio
El proceso en el runtime nunca corre como root.
Stack Bun / Node
FROM oven/bun:1.3.14-alpine
# La imagen oven/bun incluye el usuario `bun` (uid 1000)
COPY --chown=bun:bun . .
USER bun
Stack Caddy (servidor web estático)
caddy:2.x-alpine no incluye el usuario caddy. Crearlo explícitamente:
FROM caddy:2.9.1-alpine
RUN addgroup -S caddy \
&& adduser -S -G caddy caddy \
&& mkdir -p /data /config /srv \
&& chown -R caddy:caddy /data /config /srv /etc/caddy
COPY --chown=caddy:caddy docker/Caddyfile /etc/caddy/Caddyfile
COPY --from=build --chown=caddy:caddy /app/build /srv
USER caddy
Stack Go / Python / otros
Crear un usuario dedicado para el proceso:
RUN addgroup -S app && adduser -S -G app app
USER app
7. Puerto 8080
Todos los servicios exponen el puerto 8080 en producción. No usar 80, 3000, 8000, ni el puerto nativo del framework sin mapear.
EXPOSE 8080
La configuración del servidor web (Caddy, nginx, etc.) debe escuchar en 0.0.0.0:8080.
8. HEALTHCHECK obligatorio
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s \
CMD wget -qO- http://localhost:8080/health > /dev/null || exit 1
Para servicios sin endpoint HTTP dedicado, usar un comando que verifique el proceso:
HEALTHCHECK --interval=30s --timeout=3s \
CMD pgrep -x myapp > /dev/null || exit 1
9. Archivos de configuración en docker/
Los archivos de configuración específicos del runtime (Caddyfile, nginx.conf, supervisord.conf, etc.) van en el directorio docker/ del repo, no en la raíz:
proyecto/
├── Dockerfile
├── docker/
│ ├── Caddyfile # configuración de Caddy
│ └── entrypoint.sh # script de entrada (si aplica)
├── src/
└── ...
COPY --chown=caddy:caddy docker/Caddyfile /etc/caddy/Caddyfile
10. .dockerignore — estructura de tres capas
# ─── Capa 1: control de versiones y metadatos del repo ────────────────────────
.git
.gitignore
.gitattributes
# ─── Capa 2: JS/TS — excluir a cualquier profundidad ─────────────────────────
# NOTA: usar **/node_modules (con **/) no node_modules.
# .gitignore aplica recursivamente; Docker NO — cada patrón es relativo
# a la raíz del contexto a menos que se use **/.
**/node_modules
build/
.docusaurus/
# ─── Capa 3: específico del proyecto ──────────────────────────────── ──────────
.env
.env.*
!.env.example
README.md
CLAUDE.md
graphify-out/
.claude/
Nunca excluir el directorio de código fuente ni los artefactos que el build stage necesita.
11. Template completo — sitio estático Bun + Caddy
Referencia para proyectos Docusaurus / static sites:
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM oven/bun:1.3.14-alpine AS build
WORKDIR /app
ENV BUN_INSTALL_CACHE_DIR=/var/cache/bun
COPY package.json bun.lock ./
RUN --mount=type=cache,target=/var/cache/bun \
bun install --frozen-lockfile
COPY . .
RUN bun run build
FROM caddy:2.9.1-alpine
RUN addgroup -S caddy \
&& adduser -S -G caddy caddy \
&& mkdir -p /data /config /srv \
&& chown -R caddy:caddy /data /config /srv /etc/caddy
COPY --chown=caddy:caddy docker/Caddyfile /etc/caddy/Caddyfile
COPY --from=build --chown=caddy:caddy /app/build /srv
USER caddy
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s \
CMD wget -qO- http://localhost:8080 > /dev/null || exit 1
12. Template completo — API Bun/Node
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM oven/bun:1.3.14-alpine AS build
WORKDIR /app
COPY package.json bun.lock ./
RUN --mount=type=cache,target=/var/cache/bun \
bun install --frozen-lockfile --production
COPY . .
FROM oven/bun:1.3.14-alpine
WORKDIR /app
COPY --from=build --chown=bun:bun /app/node_modules ./node_modules
COPY --chown=bun:bun src/ ./src/
COPY --chown=bun:bun package.json .
USER bun
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s \
CMD wget -qO- http://localhost:8080/health > /dev/null || exit 1
CMD ["bun", "run", "src/index.ts"]
13. Lo que nunca se hace en runtime
- ❌
apt-get install/apk adden el stage de runtime - ❌
bun install/npm installen el stage de runtime - ❌ Clonar repos o descargar binarios al arrancar el contenedor
- ❌ Escribir en el sistema de archivos fuera de
/tmpo volúmenes montados - ❌ Correr como root (uid 0)
- ❌ Usar
:latesto tags mutables como base
Referencias
- repo-setup — checklist de archivos estándar de cualquier repo Wiedii
- cross-platform — convenciones de compatibilidad multi-plataforma