-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathDockerfile
More file actions
137 lines (118 loc) · 6.46 KB
/
Copy pathDockerfile
File metadata and controls
137 lines (118 loc) · 6.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# syntax=docker/dockerfile:1.4
# Java for generate-api-types scripts
FROM amazoncorretto:21.0.8 AS java-base
FROM oven/bun:1.3.13-slim AS base-deps
RUN apt-get update && apt-get install -y --no-install-recommends \
curl ca-certificates unzip git \
openssl libcurl4 libssl3 dnsutils iputils-ping file && \
update-ca-certificates && \
rm -rf /var/lib/apt/lists/*
# DuckDB CLI version, pinned to @duckdb/node-api (the query engine) so the
# CLI bakes extensions into the same ~/.duckdb/extensions/v<version>/ dir
# the runtime reads. CI passes --build-arg DUCKDB_VERSION derived from the
# lockfile (the source of truth); the default below is a fallback for plain
# `docker build`, kept in sync by scripts/sync-duckdb-version.js and enforced
# by the CI consistency check.
ARG DUCKDB_VERSION=1.5.3
RUN DUCKDB_VERSION=${DUCKDB_VERSION} bash -c "curl -L https://install.duckdb.org | bash" && \
ln -s /root/.duckdb/cli/${DUCKDB_VERSION}/duckdb /usr/local/bin/duckdb && \
duckdb -c "INSTALL snowflake FROM community; LOAD snowflake; SELECT snowflake_version();" || \
echo "Snowflake verification skipped (offline build)" && \
curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
apt-get install -y nodejs && \
rm -rf /var/lib/apt/lists/*
# Builder stage
FROM oven/bun:1.3.13-slim AS builder
COPY --from=java-base /usr/lib/jvm /usr/lib/jvm
ENV JAVA_HOME=/usr/lib/jvm/java-21-amazon-corretto
ENV PATH=$JAVA_HOME/bin:$PATH
ENV NODE_ENV=production
WORKDIR /publisher
# CA certificates are required for the DuckDB extension bake (run by
# packages/server's build): without them @duckdb/node-api can't verify TLS to
# extensions.duckdb.org and every download fails with an SSL CA cert error.
# The bun:slim base ships without them.
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates && \
update-ca-certificates && \
rm -rf /var/lib/apt/lists/*
# Copy package files first for better layer caching
COPY package.json bun.lock api-doc.yaml ./
COPY packages/server/package.json ./packages/server/package.json
COPY packages/app/package.json ./packages/app/package.json
COPY packages/sdk/package.json ./packages/sdk/package.json
# Install all workspace dependencies once (cached across builds)
RUN --mount=type=cache,target=/root/.bun/install/cache \
bun install
# Build SDK first
COPY packages/sdk/ ./packages/sdk/
WORKDIR /publisher/packages/sdk
RUN --mount=type=cache,target=/root/.bun \
bun run build
# Build app
WORKDIR /publisher/packages/app
COPY packages/app/ ./
RUN --mount=type=cache,target=/root/.bun \
NODE_OPTIONS='--max-old-space-size=4096' bun run build:server
# Build server
WORKDIR /publisher/packages/server
COPY packages/server/ ./
RUN --mount=type=cache,target=/root/.bun \
bun run build:server-only
# Final image
FROM base-deps AS final
WORKDIR /publisher
# OCI image metadata — surfaces in `docker inspect`, registry UIs
# (Docker Hub / GHCR), and Docker Desktop. The description is kept short
# (some tools truncate at 80–120 chars); the `documentation` URL points
# at the root README's Docker section for build/run/mount-path details.
LABEL org.opencontainers.image.title="Malloy Publisher" \
org.opencontainers.image.description="Open-source semantic model server for Malloy (REST :4000, MCP :4040)." \
org.opencontainers.image.source="https://github.com/malloydata/publisher" \
org.opencontainers.image.documentation="https://github.com/malloydata/publisher#docker" \
org.opencontainers.image.licenses="MIT"
# Copy built artifacts from builder
COPY --from=builder /publisher/package.json /publisher/bun.lock ./
COPY --from=builder /publisher/packages/app/dist/ /publisher/packages/app/dist/
COPY --from=builder /publisher/packages/app/package.json /publisher/packages/app/package.json
COPY --from=builder /publisher/packages/server/dist/ /publisher/packages/server/dist/
COPY --from=builder /publisher/packages/server/package.json /publisher/packages/server/package.json
COPY --from=builder /publisher/packages/sdk/dist/ /publisher/packages/sdk/dist/
COPY --from=builder /publisher/packages/sdk/package.json /publisher/packages/sdk/package.json
# Install production-only deps
RUN --mount=type=cache,target=/root/.bun/install/cache \
bun install --production
# Carry over the DuckDB extensions baked during the builder stage's
# `build:server-only` (packages/server's build runs bake-duckdb-extensions).
# They live in ~/.duckdb/extensions/v<version>/, which the runtime engine reads
# at INSTALL/LOAD time -- so the server finds them on disk and skips the network
# fetch. Copying the baked cache from the builder keeps a single bake mechanism
# (the server build) instead of re-running it here. The CLI (base-deps) and
# runtime engine are pinned to the same DuckDB version, so all agree on one dir.
COPY --from=builder /root/.duckdb/extensions /root/.duckdb/extensions
# Runtime config
ARG DUCKDB_VERSION=1.5.3
ENV NODE_ENV=production
ENV PATH="/root/.duckdb/cli/${DUCKDB_VERSION}:$PATH"
RUN mkdir -p /etc/publisher
# Trust the Amazon RDS root CAs so Postgres->RDS connections verify the server
# certificate out of the box. Node/Bun ignore the OS trust store and use their
# own bundled CA set, so NODE_EXTRA_CA_CERTS is the load-bearing knob (it appends
# to that set). Fetched at build (curl is in base-deps) rather than vendored, so
# there is no committed cert to keep fresh: a CA rotation is picked up on the next
# image build/release, and every consumer of this image (the worker, the
# SSH-bastion connection path) inherits the trust anchor without re-mounting a CA.
RUN curl -fsSL https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem \
-o /etc/ssl/certs/rds-global-bundle.pem
ENV NODE_EXTRA_CA_CERTS=/etc/ssl/certs/rds-global-bundle.pem
# Declare the runtime ports so `docker run -P` and Docker Desktop's
# port-preview surface them. The server listens on both (REST on 4000, MCP on
# 4040); this just makes them discoverable.
EXPOSE 4000 4040
# Pass --server_root explicitly so the zero-arg bundled-default trigger
# in server.ts (added for `npx @malloy-publisher/server` UX) does NOT fire
# inside the production container. Without this, a Docker image launched
# with no mounted config would try to clone the bundled DuckDB samples
# from GitHub at startup, blowing past the docker_smoke_test 90s timeout.
# Operators that want a config provide it at /publisher/publisher.config.json
# (mount as volume) or override CMD with --config <path>.
CMD ["bun", "run", "./packages/server/dist/server.mjs", "--server_root", "/publisher"]