revali_docker is a build construct that writes a Dockerfile for your server to
.revali/build/Dockerfile every time you run revali build. The image contains only the AOT-compiled server on Alpine Linux. It has no options.
Installation#
dart pub add --dev revali_docker
dev_dependencies:
revali: ^3.3.3
revali_docker: ^1.2.0
Nothing goes in revali.yaml.
Listen on all interfaces#
A server bound to localhost inside a container refuses every connection from outside it, while looking healthy. Build your app with
AppConfig.fromEnv(), which binds 0.0.0.0 and reads the port from PORT
(default 8080):
import 'package:revali_router/revali_router.dart';
@App()
final class MainApp extends AppConfig {
MainApp() : super.fromEnv();
}
See Environment Variables for HOST, PORT
and other runtime settings.
Build and run#
dart run revali build
docker build -f .revali/build/Dockerfile -t my-app .
docker run -p 8080:8080 my-app
Run docker build from the project root: the Dockerfile copies the whole project into the image.
The server answers /healthz and /readyz
out of the box, outside the /api prefix, for your platform's health checks.
The generated Dockerfile#
Without a build: section in revali.yaml, the Dockerfile compiles the server inside Docker:
FROM dart:stable AS build
WORKDIR /app
COPY . .
RUN rm pubspec_overrides.yaml || true
# Get dependencies
RUN dart pub get
# Build the server
RUN dart run revali build --release --type constructs --recompile
# Compile the server
RUN dart compile exe .revali/server/server.dart -o /app/server
FROM alpine:latest
# Install necessary dependencies for the Dart binary
RUN apk add --no-cache libc6-compat ca-certificates
# Copy the compiled server to the image
COPY --from=build /app/server /app/bin/server
# Run the server
CMD ["/app/bin/server"]
-
The mode flag follows your command:
revali build --profilewrites--profile.--releaseis the default. -
revali build --flavor <name>adds--flavor <name>to the in-container build. -
pubspec_overrides.yamlis deleted inside the image, because local path overrides do not exist there. Dependencies must resolve frompubspec.yamlalone.
--dart-define values#
Defines passed to revali build become build arguments. Only the names go into the Dockerfile, so the values given to
revali build are not used by the image. Supply the real values at image build time:
dart run revali build --dart-define=API_KEY=dev --dart-define=REGION=dev
docker build --build-arg API_KEY=prod-key --build-arg REGION=eu \
-f .revali/build/Dockerfile -t my-app .
# Define build arguments
ARG API_KEY
ARG REGION
RUN dart compile exe .revali/server/server.dart -o /app/server -DAPI_KEY=$API_KEY \
-DREGION=$REGION
Cross-compiling#
Add a build: section to revali.yaml and revali build compiles the server on your machine with
dart compile exe --target-os --target-arch. Cross-compiling to Linux works from macOS, Windows or Linux with no extra toolchain.
build:
target_os: linux
target_arch: [x64, arm64]
revali_docker then copies each binary into .revali/build/ as server-<arch>
(server-amd64, server-arm64, ...) and writes a single-stage Dockerfile around them:
FROM alpine:latest
# Install necessary dependencies for the Dart binary
RUN apk add --no-cache libc6-compat ca-certificates
ARG TARGETARCH
COPY .revali/build/server-${TARGETARCH} /app/bin/server
RUN chmod +x /app/bin/server
# Run the server
CMD ["/app/bin/server"]
With one architecture the COPY names the file directly instead of using TARGETARCH. With several, build them in one go with buildx:
docker buildx build --platform linux/amd64,linux/arm64 \
-f .revali/build/Dockerfile -t my-app .
In this mode --dart-define values are compiled into the binary at revali build
time, not passed as build arguments. Native (FFI) libraries your app loads are not cross-compiled. See
Compiling a native executable for strip_debug_info
and the other build: keys.
If your .dockerignore excludes .revali/, re-include the binaries. Docker cannot re-include a path whose parent directory is excluded, so exclude the children instead:
.revali/*
!.revali/build
Deploying#
The image runs on any container platform. Set PORT if the platform assigns one, point its health check at
/healthz, and set runtime secrets as environment variables. For a step-by-step example, see
Deploy to Fly.io. To run several services together, see
revali compose.