Skip to content

Latest commit

 

History

History
101 lines (73 loc) · 3.58 KB

File metadata and controls

101 lines (73 loc) · 3.58 KB

Docker

Hermit is published to DockerHub as beavuck/hermit. The image is a statically-linked binary running on a scratch base -- no OS, no shell, minimal attack surface. It supports linux/amd64 and linux/arm64.

Building locally

To build the docker image locally, do make sure to auth first, as we're using a Docker Hardened Image:

echo "$DOCKERHUB_WRITE_TOKEN" | docker login --username "$DOCKERHUB_USERNAME" --password-stdin

To build and load a single-platform image for local testing:

docker build --load --tag "beavuck/hermit" .

To verify the multi-platform build locally, you need a buildx builder that uses the docker-container driver (the default docker driver does not support multi-platform). Create one once:

docker buildx create --name multiarch --use

Multi-platform images cannot be loaded into the local Docker daemon -- they must be pushed directly to a registry or stay in the build cache:

docker buildx build --platform linux/amd64,linux/arm64 --tag "beavuck/hermit" .

To also push, you may add --push. But the CI pipeline should take care of that, typically.

Running

Mount your OpenAPI spec files into /specs. Use HERMIT_SPECS_DIR to load all files in a directory:

docker run --rm --pull=always \
  -p 8532:8532 \
  -v ./specs_assets:/specs:ro \
  -e HERMIT_SPECS_DIR=specs \
  beavuck/hermit

Or use HERMIT_SPECS to load specific files (comma-separated):

docker run --rm --pull=always \
  -p 8532:8532 \
  -v ./specs_assets:/specs:ro \
  -e HERMIT_SPECS=specs/taskflow.openapi.yml,specs/dog_cafe.openapi.json \
  beavuck/hermit

HERMIT_SPECS_DIR and HERMIT_SPECS are mutually exclusive -- exactly one must be provided.

Environment variables

See options.md.

docker-compose

Here is a docker-compose example of a typical Hermit setup:

  hermit:
    image: beavuck/hermit:latest
    pull_policy: always
    environment:
      HERMIT_SPECS_DIR: specs
    ports:
      - "8532:8532"
    volumes:
      - ./specs_assets:/specs:ro

Design notes

scratch base -- the binary is compiled with RUSTFLAGS="-C target-feature=+crt-static" targeting a musl Linux triple, producing a fully static binary with no libc dependency.

Multi-platform build -- the Dockerfile uses --platform=$BUILDPLATFORM on the builder stage so it always runs natively on the CI host, regardless of the target architecture. ARG TARGETARCH receives the target from docker buildx (amd64 or arm64) and is mapped to the corresponding Rust target triple. cargo-zigbuild uses zig as a cross-compiler, eliminating the need for platform-specific C toolchains.

Fixed binary path before scratch -- the builder copies the binary to /hermit-bin before the final stage. scratch has no shell, so COPY --from=builder cannot evaluate $(cat /rust_target). A fixed path sidesteps this.

PID 1 signal handling -- Linux gives PID 1 special treatment: it ignores signals unless it explicitly handles them. Without a signal handler, docker stop would wait 10 seconds then force-kill the container. Hermit registers handlers for both SIGTERM and SIGINT so it shuts down immediately.

--target flag and proc-macros -- building without an explicit target on the Alpine builder uses x86_64-alpine-linux-musl as the host target, which applies RUSTFLAGS to all crates including proc-macros. Proc-macro crates must be compiled as dylibs, which is incompatible with crt-static on musl. Specifying --target separates host builds (proc-macros, no RUSTFLAGS) from target builds (the binary, with RUSTFLAGS).