Ir al contenido

Buscar en la documentación

Busca en la documentación de Skiffly

Docker

Despliega desde un Dockerfile o una imagen ya construida en Skiffly — cuándo se usa el Dockerfile, el contexto de build y `dockerfilePath`, build args y secretos de BuildKit, `PORT`, `CMD` frente al comando de inicio, health checks, usuarios, volúmenes y los runtimes gVisor/Kata.

Hay dos formas de ejecutar una imagen de contenedor en Skiffly:

OrigenCómo se construyeSe despliega con
Repositorio con un DockerfileSkiffly lo construye con BuildKit en una microVM de Kata y sube la imagen al registro del nodocada push, skiffly up, volver a desplegar
Imagen (ghcr.io/acme/api:1.4, nginx:1.27)no se construye; el nodo la descargaskiffly deploy --image, un cambio de tag, volver a desplegar

Los registros privados todavía no están soportados: sube la imagen a un registro público (paquetes públicos de GHCR, Docker Hub) o construye desde el repositorio.

Cuándo se usa el Dockerfile#

Un Dockerfile en la raíz del repositorio — o en el directorio raíz del servicio — cambia automáticamente el builder de Railpack a Dockerfile. Para forzar uno u otro, define builder: RAILPACK | DOCKERFILE; para usar un archivo con otro nombre o ubicación, define dockerfilePath (docker/Dockerfile.prod, que se resuelve primero dentro del directorio raíz y luego desde la raíz del repositorio). El contexto de build es el directorio raíz, así que las rutas de COPY son relativas a él; un Dockerfile de monorepo que necesite todo el repositorio mantiene el directorio raíz en / y usa dockerfilePath: apps/api/Dockerfile.

skiffly api 'mutation { serviceUpdate(id: "…", input: { builder: DOCKERFILE, dockerfilePath: "docker/Dockerfile.prod" }) { id } }'

o en configuración como código: build: { builder: "DOCKERFILE", dockerfilePath: "docker/Dockerfile.prod" }. El panel muestra el builder en Configuración → Build; update-service de MCP acepta los mismos campos. Se respeta .dockerignore.

Variables y secretos en tiempo de build#

Por defecto, el build se ejecuta sin ninguna de tus variables en su entorno. Hay dos mecanismos:

  • Build args — enumera los nombres de las variables en una variable del servicio SKIFFLY_BUILD_ARGS=NODE_ENV,NEXT_PUBLIC_API_URL; esas se pasan como --build-arg y deben declararse con ARG en el Dockerfile. Los build args quedan en el historial de la imagen, así que no incluyas secretos en esta lista.
  • Secretos — cada variable del servicio está disponible como secreto de BuildKit con el nombre de la variable:
RUN --mount=type=secret,id=NPM_TOKEN \
    NPM_TOKEN=$(cat /run/secrets/NPM_TOKEN) npm ci

El log del build indica qué build args se pasaron ([build] build-args: …). Los builds tienen acceso a internet pero no pueden llegar a la red privada de tu proyecto: nada en el Dockerfile puede comunicarse con tu base de datos.

Puerto#

Skiffly define PORT en el contenedor y enruta el tráfico al puerto del servicio (8080 cuando el servicio no define uno). EXPOSE es solo informativo. Haz que el proceso lea PORT o define el puerto del servicio como el puerto en el que escucha la imagen:

ENV PORT=8080
CMD ["sh", "-c", "./server --port $PORT"]     # forma shell para que $PORT se expanda

Para una imagen que escucha en un puerto fijo (nginx en el 80, ghost en el 2368): skiffly deploy --image ghost:5 --port 2368, o Configuración → Red → Puerto. Escucha en 0.0.0.0, no en 127.0.0.1.

CMD, ENTRYPOINT y el comando de inicio#

El ENTRYPOINT/CMD de la imagen se ejecutan como de costumbre. Un comando de inicio en el servicio reemplaza el CMD (el ENTRYPOINT se conserva), así que sh -c "npm run migrate && node server.js" funciona con una imagen cuyo entrypoint es docker-entrypoint.sh. No hay fase de release; consulta la sección de migraciones de la página de tu lenguaje, o ejecuta comandos puntuales con skiffly ssh -- <cmd>.

Health check#

El HEALTHCHECK del Dockerfile se ignora. En su lugar, define una ruta del health check en el servicio; sin ella, el nodo solo comprueba que el puerto acepte conexiones TCP. Las imágenes distroless y scratch funcionan (el sondeo no necesita shell, es HTTP/TCP desde el nodo), pero entonces skiffly ssh no tiene nada que ejecutar y un comando de inicio con sh -c falla — conserva sh en la imagen si necesitas cualquiera de los dos.

Usuarios, sistema de archivos y volúmenes#

  • Los contenedores se ejecutan con el usuario que declara la imagen; correr como root funciona, pero es mejor no hacerlo (USER node). El sistema de archivos raíz es escribible y efímero.
  • Los volúmenes se montan en una ruta (skiffly volume add --mount-path /data) y pertenecen a root en el primer montaje; un proceso que no es root necesita un chown del directorio — hazlo en un script de entrypoint, o corre como root en el primer arranque.
  • Las imágenes que esperan funciones específicas de Docker (--privileged, /var/run/docker.sock, red del host) no se ejecutan.

Runtime: gVisor o Kata#

Los servicios se ejecutan con gVisor por defecto. Las imágenes que necesitan un kernel completo — bases de datos que dependen de io_uring, FUSE, trucos con SO_REUSEPORT, algunos runtimes con JIT — deberían usar Kata (runtimeClass: kata, Configuración → Runtime). Los síntomas de un runtime equivocado son errores operation not permitted/function not implemented al arrancar. Más detalles en Seguridad.

Ejemplo multi-stage#

Dockerfile
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN --mount=type=secret,id=NPM_TOKEN \
    NPM_TOKEN=$(cat /run/secrets/NPM_TOKEN 2>/dev/null || true) npm ci
COPY . .
RUN npm run build
 
FROM node:22-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
COPY package.json .
USER node
CMD ["node", "dist/server.js"]

La imagen escucha en PORT en dist/server.js; define /healthz como ruta del health check. La caché de capas se conserva por servicio entre builds, así que pon COPY package*.json antes de COPY . ..

Problemas comunes#

SíntomaSolución
Railpack se ejecuta aunque hay un Dockerfileel archivo está fuera del directorio raíz del servicio, o builder está fijado en RAILPACK
failed to solve: … "/app/dist": not foundel contexto de build es el directorio raíz; revisa las rutas de COPY y .dockerignore
ARG está vacío durante el buildagrega el nombre de la variable a SKIFFLY_BUILD_ARGS
ImagePullBackOff en el mensaje del despliegueerror de tipeo en el nombre/tag de la imagen, o un registro privado (no soportado)
FAILED a los 5 minutosel proceso escucha en un puerto distinto de PORT/el puerto del servicio, o en 127.0.0.1
permission denied al escribir en un volumenel montaje pertenece a root: haz chown en un entrypoint o corre como root
Errores function not implemented, io_uring_setupcambia el servicio al runtime Kata
exec: "sh": not found con un comando de inicioimagen distroless: define el comando de inicio como el ejecutable mismo, sin sh -c

Landing: /deploy/docker